实体框架在添加没有 ID 的数据时引发错误

Entity Framework throwing an error when adding data without IDs

提问人:Asbah Qadeer 提问时间:8/16/2017 最后编辑:Joe MayoAsbah Qadeer 更新时间:8/17/2017 访问量:323

问:

我有一个函数,它返回推文列表。该列表中的每个元素都有很多数据,推文的文本、位置、用户信息(如果是转发)、时间、转发信息、图片链接,以及更多数据,彼此之间的数据列表。

我正在使用 Linq2Twitter 包,它为我提供了一个名为 Status 的对象,这就是我所说的推文。

此代码从我的函数中获取数据:var container = await DoPagedSearchAsync(context, this);

我的 DBSet 如下所示:

       public class TweetContext : DbContext
    {
        public DbSet<Status> Tweets { get; set; }
    }

我正在尝试使用以下代码添加数据:

        using (var vontex = new TweetContext())
        {
            vontex.Tweets.AddRange(container);
            vontex.SaveChanges();
        }

以下是我在运行时在线上遇到的错误列表:vontex.Tweets.AddRange(container);

在模型生成过程中检测到一个或多个验证错误:

DataAcquirer.Models.Status::EntityType“Status”未定义任何键。定义此 EntityType 的键。 DataAcquirer.Models.Coordinate::EntityType“Coordinate”未定义键。定义此 EntityType 的键。 DataAcquirer.Models.Entities::EntityType“Entities”未定义键。>定义此 EntityType 的键。 DataAcquirer.Models.HashTagEntity::EntityType 'HashTagEntity' 未定义任何键。定义此 EntityType 的键。 DataAcquirer.Models.PhotoSize::EntityType 'PhotoSize' 未定义键。定义此 EntityType 的键。 DataAcquirer.Models.VideoInfo::EntityType“VideoInfo”未定义任何键。定义此 EntityType 的键。 DataAcquirer.Models.Variant::EntityType“Variant”未定义键。定义此 EntityType 的键。 DataAcquirer.Models.SymbolEntity::EntityType 'SymbolEntity' 未定义任何键。定义此 EntityType 的键。 DataAcquirer.Models.UrlEntity::EntityType 'UrlEntity' 未定义任何键。定义此 EntityType 的键。 DataAcquirer.Models.UserMentionEntity::EntityType 'UserMentionEntity' 未定义键。定义此 EntityType 的键。 DataAcquirer.Models.Geometry:EntityType 'Geometry' 未定义键。定义此 EntityType 的键。 DataAcquirer.Models.User::EntityType“User”未定义任何键。定义此 EntityType 的键。 DataAcquirer.Models.BannerSize::EntityType 'BannerSize' 未定义键。定义此 EntityType 的键。 DataAcquirer.Models.Category::EntityType“Category”未定义任何键。定义此 EntityType 的键。 推文:EntityType:EntitySet“推文”基于未定义键的类型“Status”。 坐标:EntityType:EntitySet“坐标”基于未定义键的“坐标”类型。 实体:EntityType:EntitySet“实体”基于未定义键的“实体”类型。 HashTagEntities:EntityType:EntitySet“HashTagEntities”基于未定义键的类型“HashTagEntity”。 PhotoSizes:EntityType:EntitySet“PhotoSizes”基于未定义键的“PhotoSize”类型。 VideoInfoes:EntityType:EntitySet“VideoInfoes”基于未定义键的类型“VideoInfo”。 变体:EntityType:EntitySet“Variants”基于未定义键的类型“Variant”。 SymbolEntities:EntityType:EntitySet“SymbolEntities”基于未定义键的类型“SymbolEntity”。 UrlEntities:EntityType:EntitySet“UrlEntities”基于未定义键的类型“UrlEntity”。 UserMentionEntities:EntityType:EntitySet“UserMentionEntities”基于未定义键的类型“UserMentionEntity”。 Geometries: EntityType: EntitySet 'Geometries' 基于未定义键的 'Geometry' 类型。 用户:EntityType:EntitySet“Users”基于未定义键的类型“User”。 BannerSizes:EntityType:EntitySet“BannerSizes”基于未定义键的“BannerSize”类型。 类别:EntityType:EntitySet“类别”基于未定义键的类型“Category”。

该类如下所示:

using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using LitJson;

namespace LinqToTwitter
{
 [XmlType(Namespace = "LinqToTwitter")]
 public class Status
 {
    public Status();
    public Status(JsonData status);

    public Annotation Annotation { get; set; }
    public List<Contributor> Contributors { get; set; }
    public Coordinate Coordinates { get; set; }
    public int Count { get; set; }
    public DateTime CreatedAt { get; set; }
    public ulong CurrentUserRetweet { get; set; }
    public long Cursor { get; set; }
    public Cursors CursorMovement { get; set; }
    public EmbeddedStatus EmbeddedStatus { get; set; }
    public Entities Entities { get; set; }
    public bool ExcludeReplies { get; set; }
    public Entities ExtendedEntities { get; set; }
    public int? FavoriteCount { get; set; }
    public bool Favorited { get; set; }
    public FilterLevel FilterLevel { get; set; }
    public ulong ID { get; set; }
    public bool IncludeContributorDetails { get; set; }
    public bool IncludeEntities { get; set; }
    public bool IncludeMyRetweet { get; set; }
    public bool IncludeRetweets { get; set; }
    public bool IncludeUserEntities { get; set; }
    public string InReplyToScreenName { get; set; }
    public ulong InReplyToStatusID { get; set; }
    public ulong InReplyToUserID { get; set; }
    public string Lang { get; set; }
    public bool Map { get; set; }
    public ulong MaxID { get; set; }
    public StatusMetaData MetaData { get; set; }
    public EmbeddedStatusAlignment OEmbedAlign { get; set; }
    public bool OEmbedHideMedia { get; set; }
    public bool OEmbedHideThread { get; set; }
    public string OEmbedLanguage { get; set; }
    public int OEmbedMaxWidth { get; set; }
    public bool OEmbedOmitScript { get; set; }
    public string OEmbedRelated { get; set; }
    public string OEmbedUrl { get; set; }
    public Place Place { get; set; }
    public bool PossiblySensitive { get; set; }
    public Status QuotedStatus { get; set; }
    public ulong QuotedStatusID { get; set; }
    public int RetweetCount { get; set; }
    public bool Retweeted { get; set; }
    public Status RetweetedStatus { get; set; }
    [XmlIgnore]
    public Dictionary<string, string> Scopes { get; set; }
    public string ScreenName { get; set; }
    public ulong SinceID { get; set; }
    public string Source { get; set; }
    public ulong StatusID { get; set; }
    public string Text { get; set; }
    public bool TrimUser { get; set; }
    public bool Truncated { get; set; }
    public string TweetIDs { get; set; }
    [XmlIgnore]
    public StatusType Type { get; set; }
    public User User { get; set; }
    public ulong UserID { get; set; }
    public List<ulong> Users { get; set; }
    public bool WithheldCopyright { get; set; }
    public List<string> WithheldInCountries { get; set; }
    public string WithheldScope { get; set; }
 }
}

上述模型无法编辑。它带有 Linq2Twitter 包。

C# 数据库 实体框架 linq-to-twitter

评论

0赞 pisi1001 8/16/2017
在您的 ID 上使用 [Key] 数据注释。 检查此链接 entityframeworktutorial.net/code-first/...
0赞 Asbah Qadeer 8/16/2017
我无法编辑模型,它随包一起提供
0赞 llouk 8/16/2017
创建一个新模型并传输您需要的数据。实体将无法保存所有复杂的数据类型。
0赞 Asbah Qadeer 8/16/2017
实体不会按原样保存它,但它将能够保存它,我以前保存过真正复杂的模型。我会创建自己的模型,但该模型非常冗长和复杂。这就是我使用 codefirst 的灵魂原因
0赞 llouk 8/16/2017
“实体不会按原样保存它,但它将能够保存它”实体不会保存它,只要你不能编辑它。

答:

0赞 Juan 8/16/2017 #1

如果您计划手动创建 ID,则可以从 Status 继承并添加如下内容:

 [DatabaseGe‌​nerated(DatabaseGen‌​eratedOption.None)]
 public Guid Id { get; set; }

或使用注释中所述的 Key 属性 (http://www.entityframeworktutorial.net/code-first/key-dataannotations-attribute-in-code-first.aspx)

[Key]
 public Guid Id { get; set; }

我希望它有所帮助。

评论

0赞 DevilSuichiro 8/16/2017
请注意,这两种修改都具有截然不同的效果。DatabaseGeneratedOption.None 仅表示该值不是由数据库生成的,PK 部分只是通过命名约定完成的。这也意味着在这两种方法中都不需要 [Key] 属性。这也意味着第二种方法与仅声明属性没有区别,这也使列 DatabaseGeneratedOption.Identity,而另一种方法则没有(与直接代码优先约定的唯一区别)。
0赞 Juan 8/17/2017
没错,我忘了谈论 EF 命名约定,我的答案中的重点是继承和新的 Id 属性。
0赞 Richard Hernandez 8/16/2017 #2

您是否查看过 System.Data.Entity.ModelConfiguration.EntityTypeConfiguration

您可以创建地图:

public class StatusMap : EntityTypeConfiguration<Status>
{
     public StatusMap()
     {
         ToTable("StatusTable")
         .HasKey(p => p.ID);
     }
}

然后,在上下文中,您可以添加:

protected override void OnModelCreating([NotNull] DbModelBuilder modelBuilder)
{
     modelBuilder.Configurations.Add(new StatusMap());
}
1赞 Joe Mayo 8/17/2017 #3

这种方法是行不通的。Twitter API 返回分层对象,而不是关系对象。例如,下面是 LINQ to Twitter 使用的代码片段:

{
  "retweeted":false,
  "in_reply_to_screen_name":null,
  "possibly_sensitive":false,
  "retweeted_status":{
     "retweeted":false,
     ...,
     "user":{
        "id":41754227,
        ...
     },
     ...
  },
  "contributors":null,
  "coordinates":{
      "type":"Point",
      "coordinates":[
          -122.40060,
          37.78215
      ]
  },
  "place":null,
  "user":{
     "id":15411837,
     ...
  },
  "retweet_count":393,
  ...
}

LINQ to Twitter 将其转换为一种类型,并且该类型具有一些习惯用语,以便更轻松地生成 LINQ 子句。仍然是分层的。TweetTweetwhereTweet

要了解 的层次结构,请注意上面的 JSON 在 下有更复杂的对象,例如 (LINQ to Twitter 中的 RetweetedStatus),它是 的 类型属性,也是 的类型属性。内部和是更复杂的对象。TweetTweetretweeted_statusTweetTweetuserUserTweetRetweetedStatusUser

对于您看到的问题,请注意属性。它没有,因为它主要是一个值。也许它更适合建模为语义结构,也许这是我在这里的收获之一,但事实是它没有,也永远不会有一个.如果浏览错误消息中的项列表,您将看到大多数错误都针对值类型对象,例如 .coordinatesIDIDcoordinates

一种方法是不保留在关系模型中,而是寻找满足您需求的 NoSQL 选项。例如MongoDB或Microsoft的新CosmosDB - 还有无数的选择。我在自己的代码中采用了这种方法,因为虽然现在的 Twitter API 更加严格,但它过去的变化是不可预测的。也就是说,如今关系方法可能是可行的。在这种方法中,你可以像这样从Twitter上读取原始内容:

string jsonResults = vontex.RawResults;

然后,您可以使用 Json.NET 提取单个推文。

以下是我将使用关系方法执行的操作:

  1. 使用自动映射器。学习这个工具所花费的少量时间不仅会给这个项目带来很多好处,而且会在未来带来很多好处。
  2. 创建适合关系持久性的自己的对象。Tweet
  3. 使用关系引用将转发的状态引用回原始推文。
  4. 创建一个 User 表,并创建从 到 .TweetUser
  5. 对于所有值类型对象,您有两个选项: 一个。如果它是单个值,例如 ,则将其展平为 . b.如果它是多值,例如 ,则创建一个单独的表,其中实体具有自己的伪键并引用回 .coordinatesTweetentitiesTweet

我知道你想看代码。然而,这是一项艰巨的工作,编写代码相当于我为你编写整个数据访问层,这对于论坛的答案来说是不合理的。我仍然会走NoSQL路线,除非有硬性要求去关系。希望这会有所帮助。

评论

1赞 Asbah Qadeer 8/17/2017
这实际上是我一直在寻找的。帮了大忙,是的,我确实使用自动映射器。现在,我创建了自己的模型,扁平化了我需要的数据,并且现在坚持使用 SQL,因为大量数据与我的项目无关。再次感谢一吨清除这个问题。