如何指定属性生成TEXT列而不是nvarchar(4000)?

53

我正在使用Entity Framework的Code First特性,并且正在尝试弄清楚如何在自动生成数据库时指定应创建哪些列数据类型。

我有一个简单的模型:

public class Article
{
    public int ArticleID { get; set; }

    public string Title { get; set; }
    public string Author { get; set; }
    public string Summary { get; set; }
    public string SummaryHtml { get; set; }
    public string Body { get; set; }
    public string BodyHtml { get; set; }
    public string Slug { get; set; }

    public DateTime Published { get; set; }
    public DateTime Updated { get; set; }

    public virtual ICollection<Comment> Comments { get; set; }
}
当我运行我的应用程序时,会自动创建一个具有以下架构的SQL CE 4.0数据库: DB Schema 目前为止,一切顺利!然而,我将插入到BodyBodyHtml属性中的数据通常大于NVarChar列类型允许的最大长度,因此我希望EF为这些属性生成Text列。
但是,我似乎找不到方法来实现这一点!经过一番谷歌搜索和阅读后,我尝试使用DataAnnotations指定列类型,从这个答案中获得了信息:
using System.ComponentModel.DataAnnotations;

...

[Column(TypeName = "Text")]
public string Body { get; set; }

当数据库被删除并重新运行应用程序时,会引发以下异常:

Schema specified is not valid. Errors: (12,6) : error 0040: The Type text is not qualified with a namespace or alias. Only PrimitiveTypes can be used without qualification.

但是我不知道应该指定哪个命名空间或别名,也没有找到任何能告诉我的东西。

我还尝试根据这个参考链接更改注释:

using System.Data.Linq.Mapping;

...

[Column(DbType = "Text")]
public string Body { get; set; }
在这种情况下,数据库确实被创建了,但是Body列仍然是一个NVarChar(4000),因此似乎注释被忽略了。
有人能帮忙吗?这似乎应该是一个相当常见的需求,但我的搜索一直没有结果!

3
CE支持文本吗?在数据类型列表中,我可以看到ntext,但没有text。 - Damien_The_Unbeliever
@Damien,你说得对,谢谢 - 请将此作为答案添加(并添加数据类型列表的链接),我会接受它。 - Mark Bell
我找不到数据类型的在线列表 - 我不得不下载CE BOL进行检查。看起来Kristof Claes已经添加了一个涵盖相同内容的答案。 - Damien_The_Unbeliever
@Damien - 是的,对不起。当我开始打我的答案时,我没有看到你的评论。 - Kristof Claes
那我就接受Kristof的答案了,谢谢大家的帮助! - Mark Bell
12个回答

82

我很感谢已有答案所做出的努力,但我并没有发现它真正回答了我的问题...因此我进行了测试,发现

[Column(TypeName = "ntext")]
public string Body { get; set; }

使用来自System.ComponentModel.DataAnnotations的属性可以创建一个ntext类型的列。

我对被接受的答案有疑问,因为它似乎表明您应该在界面中更改列类型,但问题是如何以编程方式完成。


3
当你尝试插入超过4,000个字符时,模型验证仍然会出现问题并引发错误,即使数据库设置为ntext类型。但是似乎当它读取“字符串”类型时,它会自动猜测最大长度为4,000,忽略数据库中的类型。对我来说问题仍未解决。 - Nestor

33

你可以使用以下DataAnnotation,Code-First将生成数据库允许的最大数据类型。在Sql CE的情况下,它会生成底层的ntext列。

[MaxLength]

或使用 EF 4.1 RC 流畅的 API...

protected override void OnModelCreating(ModelBuilder modelBuilder){
    modelBuilder.Entity<Article>()
        .Property(p => p.Body)
        .IsMaxLength();
}

2
对于仍在使用 SQL Server CE + EF Code-First 的人来说,如果您尝试了 typeName=ntext 但仍然遇到“该字段必须是字符串或数组类型,并且最大长度为 '4000'”的错误,那么这就是您要寻找的解决方案 …… 只需要在列上使用 [MaxLength] 就可以将其设置为 ntext,并允许使用完整的数据长度。 - Rich

9
你试过使用ntext吗?我刚刚创建了一个SQL CE 4.0数据库,当我手动向表中添加列时,我注意到text不在数据类型列表中,而ntext是。就像你可以选择nvarchar但不能选varchar一样。

不幸的是,你可以选择的最大nvarchar大小为4000。所以nvarchar(max)也不是一个选择。

There is ntext but no text


但是您如何定义模型,以便模型验证可以理解为ntext,而不是字符串(默认max = 4,000)。我已将ntext设置为我的数据库,但在添加超过4,000个字符时仍然会出现错误。我的模型属性是字符串类型。 - Nestor
你尝试在字符串属性上加上[Column(TypeName = "ntext")]了吗? - Kristof Claes
是的,但这还不够,我添加了[MaxLength]来强制检查数据库中字段的大小,而不是默认的字符串类型最大长度,现在没问题了。 - Nestor

7

6
使用字符串长度属性(例如)存在问题。
[StringLength(4010)]

任何字符数量超过属性定义的字符数的字符串都会触发验证异常,这有点违反在列上使用非定义字段大小的原因,或者您在属性中使用了一个巨大的数字并失去了属性提供的任何验证。如果使用StringLength属性,则最终是使用验证机制来解决映射问题,而Marcel Popescu的答案使用Column属性是一个更好的解决方案,因为它使用映射属性来定义类型,并仍然允许您使用StringLength属性进行验证。

另一种选择是使用EF4 CTP5流畅API并在DbContext的OnModelCreating事件中定义列映射,例如:

protected override void OnModelCreating(ModelBuilder modelBuilder){
    modelBuilder.Entity<Article>()
    .Property(p => p.Body)
    .HasColumnType("nvarchar(max)");
}

值得注意的是,NText是一种废弃的数据类型(ntext、text和image (Transact-SQL)MS Books Online),推荐使用NVarChar(MAX)替代其功能。


1
对于 MS SQL CE 并没有被弃用,这里的问题提到了 MS SQL CE(4)的情况。 - Nestor
2
刚刚检查了Sql CE 4.0文档(http://msdn.microsoft.com/en-us/library/ms172424%28v=SQL.110%29.aspx),但是ntext类型无法与任何(sql server)字符串函数一起使用,并且它将数据存储在表的其他数据页中,因此个人认为除非我有非常明确的理由,否则出于性能和功能原因,我会坚持使用nvarchar(max)。 - nakchak

5
我知道,可能已经晚了一年,但是:
使用:
[StringLength(-1)] 

这将创建一个nText字段。我成功地使用Compact Edition 4.0数据库在该字段中存储了至少25K字节的数据。

1
这个DataAnnotation将使Code-First在SQL中生成一个nvarchar(MAX)列。
[StringLength(1073741822)]

不确定其他大数字是否也是如此...我使用计算器和nvarchar(MAX)规范得到了这个数字。

我已经尝试过SQL Server 2005 Express,但没有尝试过CE

我正在使用它,它有效,但我想知道这是否是一个好主意,或者我是否遗漏了什么...是否有其他方法让代码优先知道我想要nvarchar(MAX)?


1

这个数据注释会让 Code-First 在 SQL 中生成一个 nvarchar(MAX) 列 :)

[StringLength(4010)]

1

同意 TypeName = "ntext" 似乎可行,尽管我还需要添加:

[StringLength(Int32.MaxValue)]

为了避免默认的字符串长度128成为阻碍,需要进行处理。

1
这在 SQL CE 上不起作用。请参考 Michael 在这里使用 [MaxLength] 的答案。 - LordHits

1

如果您使用包管理器添加迁移并更新数据库,则可以通过添加storeType来修改创建表,如下所示:

       CreateTable(
            "dbo.Table_Name",
            c => new
                {
                    ID = c.Int(nullable: false, identity: true),
                    Title = c.String(nullable: false, maxLength: 500),
                    Body = c.String(unicode: false, storeType: "ntext"),
                })
            .PrimaryKey(t => t.ID);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接