如何附加不是来自数据库的实体框架对象?

Posted

技术标签:

【中文标题】如何附加不是来自数据库的实体框架对象?【英文标题】:How can I attach an Entity Framework object that isn't from the database? 【发布时间】:2010-10-16 13:23:07 【问题描述】:

我的 Entity Framework 对象和我的 POCO 对象完全分离,我只是来回翻译它们......

即:

// poco
public class Author

   public Guid Id  get; set; 
   public string UserName  get; set; 

然后我有一个具有相同属性的 EF 对象“作者”..

所以我有我的业务对象

var author = new Author  UserName="foo", Id="Guid thats in the db" ;

我想保存这个对象,所以我做了以下事情:

var dbAuthor = new dbAuthor  Id=author.Id, UserName=author.UserName ;
entities.Attach(dbAuthor);
entities.SaveChanges();

但这给了我以下错误:

EntityKey 值为空的对象 不能附加到对象 上下文。

编辑: 看来我必须使用entities.AttachTo("Authors", dbAuthor);在没有 EntityKey 的情况下附加,但是我有硬编码的魔法字符串,如果我完全更改我的实体集名称,它会中断并且我不会有任何编译时间检查...有没有一种方法可以附加来保持编译时间检查?

我希望我能够做到这一点,因为硬编码的字符串会扼杀编译时验证 =)

【问题讨论】:

您是否查看了我的答案的编辑,它允许您在没有魔术字符串或 AttachTo 的情况下执行此操作,因为这些方法是由设计器生成并由 edmx 模型维护的。 是的,我没有添加它,我正在更新它,所以我需要附加它,并保存更改 我仍然认为您的模型存在未将 Authors 对象上的 Id 属性设置为 EntityKey 的问题,您应该仔细检查生成的 XML 并确保它嵌套在关键元素中并制作确保 Id 属性具有属性 EdmScalarPropertyAttribute(EntityKeyProperty=true) 它有: 但它没有任何关于 EdmScalarPropertyAttribute EdmScalarPropertyAttribute 将应用于模型的 Designer.cs 文件中的 Id 属性。它肯定应该有属性,但我认为可能没有指定 EntityKeyProperty 参数。 【参考方案1】:

现在才看到这个。如果您想将 Attach() 附加到 ObjectContext,即让实体框架相信数据库中已经存在实体,并且您想避免使用魔术字符串,即

ctx.AttachTo("EntitySet", entity);

你可以尝试基于扩展方法的两种可能性,这两种方法都绝对让生活更容易忍受。

第一个选项允许你写:

ctx.AttachToDefault(entity);

并在此处介绍:Tip 13 - How to attach an entity the easy way

第二个选项允许你写:

ctx.EntitySet.Attach(entity);

并在此处介绍:Tip 16 - How to mimic .NET 4.0's ObjectSet today

如您所见,两者都非常易于使用并且完全避免使用字符串。

希望对你有帮助

亚历克斯

【讨论】:

【参考方案2】:

您是否尝试过使用AttachTo 并指定实体集?..

entities.AttachTo("Authors", dbAuthor);

"Authors" 是您的实际实体集名称。

编辑: 是的,有更好的方法(应该有)。设计者应该已经为你生成了 "Add" methods 到 ObjectContext ,它转换为上面的调用。所以你应该能够做到:

entities.AddToAuthors(dbAuthor);

字面意思应该是:

public void AddToAuthors(Authors authors)

    base.AddObject("Authors", authors);

在whateverobjectcontext.designer.cs 文件中定义。

【讨论】:

这似乎确实有效,但是我到处都有“魔术字符串”,如果我重命名实体集,我的所有代码都会中断。有没有更好的方法来做到这一点? @Ashkan 您的编辑使答案不正确,自动生成的AddToAuthors 不使用EntitySet.Name,而您的编辑声称确实如此,所以我已将其还原。您的编辑背后的原则对我来说看起来不错,这就是我赞成的另一个答案中使用的内容,我鼓励您也这样做。【参考方案3】:

如果您不想使用 EntitySet 名称编写字符串,请尝试此操作

entities.AttachTo(entities.CreateObjectSet<T>().EntitySet.Name, entity);

【讨论】:

'entities.Authors.Attach(dbAuthor);'更好。【参考方案4】:

如果您不知道要对哪个实体进行操作,则可以使用以下替代方法:

string className = entityObject.GetType().Name;
var container = _DbContext.MetadataWorkspace.GetEntityContainer(_DbContext.DefaultContainerName, DataSpace.CSpace);
string setName = (from meta in container.BaseEntitySets
                  where meta.ElementType.Name == className
                  select meta.Name).First();
_DbContext.AttachTo(setName, entityObject);

【讨论】:

谢谢你,不知道你是怎么想出来的,但我在寻找一种方法来做到这一点时碰巧遇到了它。我正在使用来自codeproject.com/articles/179481/code-first-stored-procedures 的 Code First 存储过程项目,并且对未将项目添加到 DbContext 跟踪中感到不高兴。使用此代码,我能够添加它们。这并不完美,因为它们是在没有代理代码的情况下添加到延迟加载属性的,但它对我来说已经足够好了。【参考方案5】:

你可以试试关注

entities.AddToAuthors(dbAuthor);

【讨论】:

这真的是评论,而不是问题的答案。你可以随时对自己的帖子发表评论,一旦你有足够的reputation,你就可以comment on any post。 @BryanCrosby 我不同意。我相信这是一个答案,而不是评论。【参考方案6】:

对我来说,

Context.Authors.AddObject(new Author())

完美运行。想知道我是否遗漏了什么?还是方法不对?

【讨论】:

这用于新对象,而不是现有对象。

以上是关于如何附加不是来自数据库的实体框架对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何从实体框架中存在数据模型的json中反序列化对象?

Asp.net 核心 - 实体框架核心 - 将附加数据添加到视图对象,同时保持它是可查询的

Database.Log 不记录来自实体框架中的拦截器的附加 SQL

如何将 sql server express 数据库附加到实体框架中的项目

如何确定实体框架是不是正在等待来自连接池的连接?

在实体框架中将对象树附加到对象上下文