如何附加不是来自数据库的实体框架对象?
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) 它有:现在才看到这个。如果您想将 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())
完美运行。想知道我是否遗漏了什么?还是方法不对?
【讨论】:
这用于新对象,而不是现有对象。以上是关于如何附加不是来自数据库的实体框架对象?的主要内容,如果未能解决你的问题,请参考以下文章
Asp.net 核心 - 实体框架核心 - 将附加数据添加到视图对象,同时保持它是可查询的
Database.Log 不记录来自实体框架中的拦截器的附加 SQL