使用 POCO 将新记录插入到使用 linq toEntity 的链接表中
我有一个多对多关系的团队表和玩家表。有一个名为 TeamOnPlayer 的链接表。 EF 与 POCO 为团队实体生成名为 Person 的导航属性,并生成一个导航。支柱。称为 Team for the People 实体。
我试图将新记录插入到 TeamOnPlayer 表中,但 EF 和 POCO 隐藏了它。我尝试这样做:
public static void AddPersonToTeam(int TeamId, int PersonId)
{
using (var ef = new korfballReportEntities())
{
var team = GetTeam(TeamId);
var person = GetPerson(PersonId);
team.Person.Add(person);
person.Team.Add(team);
ef.SaveChanges();
}
}
GetTeam(TeamId) 和 GetPerson(PersonId) 获取正确的团队和人员:
public static Team GetTeam(int id)
{
using (var ef = new korfballReportEntities())
{
var q = from l in ef.Team
where l.Id == id
select l;
return q.Single();
}
}
public static Person GetPerson(int id)
{
using (var ef = new korfballReportEntities())
{
var query = from p in ef.Person
where p.Id == id
select p;
return query.Single();
}
}
当它尝试调用 team.Person.Add(person) 时,它会抛出异常:
“ObjectContext 实例已被释放,不能再用于需要连接的操作。” System.Exception {System.ObjectDisposeException}
任何人都可以告诉我正确的方法吗?
编辑
现在我明白了问题所在,谢谢你。我对你包含的使用块有点困惑。例如:
using (var ef = new korfballReportEntities())
{
//switch lazy loading off, only in this single context
ef.Configuration.LazyLoadingEnabled = false;
var repository = new MyRepository(ef);
repository.AddPersonToTeam(int TeamId, int PersonId);
}
我应该把它放在哪里?
我还做了别的事。我只是这样做了,而且效果很好。
public static void AddPersonToTeam(int TeamId, int PersonId)
{
using (var ef = new korfballReportEntities())
{
var q = from t in ef.Team
where t.Id == TeamId
select t;
var team = q.Single();
var q2 = from p in ef.Person
where p.Id == PersonId
select p;
var person = q2.Single();
try
{
team.Person.Add(person);
person.Team.Add(team);
}
catch (Exception e)
{
}
ef.SaveChanges();
}
}
唯一的问题是,我不能重用我的 GetPerson(int id) 和 GetTeam(int id) 方法。
你怎么认为?可以吗?这是一种丑陋的方式吗?
I have a Team table and a Player table in many to many relationship. There is a linking table called TeamOnPlayer. EF with POCO generates navigation propertie called Person for the Team entity and also generates a nav. prop. called Team for the People entity.
I'm trying to insert a new record into the TeamOnPlayer table, but EF and POCO hides it. I tried to do this:
public static void AddPersonToTeam(int TeamId, int PersonId)
{
using (var ef = new korfballReportEntities())
{
var team = GetTeam(TeamId);
var person = GetPerson(PersonId);
team.Person.Add(person);
person.Team.Add(team);
ef.SaveChanges();
}
}
The GetTeam(TeamId) and GetPerson(PersonId) gets the right team and person:
public static Team GetTeam(int id)
{
using (var ef = new korfballReportEntities())
{
var q = from l in ef.Team
where l.Id == id
select l;
return q.Single();
}
}
public static Person GetPerson(int id)
{
using (var ef = new korfballReportEntities())
{
var query = from p in ef.Person
where p.Id == id
select p;
return query.Single();
}
}
When it tries to call the team.Person.Add(person) it throws an exception:
"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection." System.Exception {System.ObjectDisposedException}
Can anyone please show me the correct way?
Edit
Now I understand what the problem was, thanks to you. I was a bit confused about the using blocks you included. For example this:
using (var ef = new korfballReportEntities())
{
//switch lazy loading off, only in this single context
ef.Configuration.LazyLoadingEnabled = false;
var repository = new MyRepository(ef);
repository.AddPersonToTeam(int TeamId, int PersonId);
}
Where should I put it?
I've done something else. I simply did this, and it worked fine.
public static void AddPersonToTeam(int TeamId, int PersonId)
{
using (var ef = new korfballReportEntities())
{
var q = from t in ef.Team
where t.Id == TeamId
select t;
var team = q.Single();
var q2 = from p in ef.Person
where p.Id == PersonId
select p;
var person = q2.Single();
try
{
team.Person.Add(person);
person.Team.Add(team);
}
catch (Exception e)
{
}
ef.SaveChanges();
}
}
The only problem is, that i coludn't reuse my GetPerson(int id) and GetTeam(int id) method.
What do you think? Is it okay? Is this an ugly way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我的猜测是您正在使用延迟加载 - 您的导航属性
Team.Person
和Person.Team
在实体类中标记为virtual
。结果是您的方法GetTeam
和GetPerson
并不完全返回Team
和Person
对象,而是动态创建的实例从这些实体派生的代理类。此动态代理支持延迟加载,这意味着当您第一次访问导航集合Team.Person
和Person.Team
时,EF 会尝试加载它们。当您对这些集合调用Add
时,这种情况会在您的AddPersonToTeam
方法中发生。现在的问题是,代理是在您立即在
GetTeam
和GetPerson
方法(在 using 块的末尾)中处置的上下文中创建的。代理已在内部存储对此上下文的引用,并将使用此上下文从数据库加载导航集合。因为这些上下文已经被释放,所以你会得到异常。
您应该稍微重新设计代码:不要在存储库方法
GetTeam
和GetPerson
中创建新上下文。您应该对所有操作使用相同的上下文:检索Team
、检索Person
并添加关系。例如:另一种方法是使“存储库”/“服务”不是静态的,将上下文注入到构造函数中,然后在整个存储库中使用此上下文。那么您不需要将上下文传递到每个方法中。粗略的草图:
编辑
关于性能调整的一点:在这种特定情况下,延迟加载是不必要的,而且更令人不安。当您只想向集合添加一个额外的
Person
时,它会导致加载一个(可能很长)集合team.Person
。您可以关闭此特定操作的延迟加载(我参考我的第二个示例):My guess is that you are working with lazy loading - your navigation properties
Team.Person
andPerson.Team
are marked asvirtual
in your entity classes. The result is that your methodsGetTeam
andGetPerson
do not exactly returnTeam
andPerson
objects but instances of dynamically created proxy classes which are derived from those entities. This dynamic proxy supports lazy loading which means that EF tries to load the navigation collectionsTeam.Person
andPerson.Team
when you access them for the first time. This happens in yourAddPersonToTeam
method when you callAdd
on these collections.Now the problem is that the proxies are created within an context which you immediately dispose in your
GetTeam
andGetPerson
methods (at the end of the using block). The proxies have stored a reference to this context internally and will use this context to load the navigation collections from the database.Because these contexts are already disposed you get the exception.
You should redesign your code a bit: Don't create a new context in your repository methods
GetTeam
andGetPerson
. You should instead use the same context for all operations: Retrieving theTeam
, retrieving thePerson
and adding the relationship. For example:Another approach is to make your "Repository"/"Service" not static, inject the context into the constructor and then use this context throughout the repository. Then you don't need to pass in the context into every method. A rough sketch:
Edit
One little thing about performance tuning: In this specific case lazy loading is not necessary and more disturbing. It causes to load a (potentially long) collection
team.Person
when you want to add only one additionalPerson
to the collection. You can switch off lazy loading for this particular operation (I refer to my second example):