Ado实体框架添加数据
我对我的实体添加功能有点麻烦。Ado实体框架添加数据
设置
为简单起见,我在DB有4个表,客户,地址,面积,位置。
- 客户存储基本客户详细信息IE浏览器。 ID,名称,用户名,密码等
- 地址商店街道名称,街道号码等
- 区域商店区域名称和区号。
- 位置商店位置名称和位置代码。
的关系如下 客户* ---> 1个地址* ---> 1区* ---> 1地点
在我的应用程序,我想有一个函数来创建一个新客户。还有一些文本框可用于地址信息。区域和位置信息可以从我从数据库中预取的可用区域和位置列表中选择,并填充到组合框中。
我的应用程序不直接使用ADO.net EF,而是通过WCF数据服务调用。该服务位于IIS托管的SQL服务器上。以下是在业务逻辑层检索客户的服务电话
/// <summary>
/// The get all customers.
/// </summary>
/// <returns>
/// </returns>
public static List<Customer> GetAll()
{
using (var context = new CustomerDataEntities())
{
// I may be missing something here.. Possibly a call to Detach().
// I have been ommitting it because a call to Detach()
// tends to cut away any .Include() from the data. Maybe there is another way?
return context.CustomerSet.ToList();
}
}
正如您所看到的。这将无限期地导致Context的多个实例(如Craig Stuntz所述,这是一个错误)。
然后在WCF数据服务中。
// IDataService.cs
[OperationContract]
List<Customer> GetAllCustomers();
// DataService.svc.cs
public List<Customer> GetAllCustomers()
{
return CustomerBLL.GetAll();
}
应用程序继续使用的客户列表从以上检索,而OPS创建一个新的客户,像这样:
private Location newLocation;
private Area newArea;
private Address newAddress;
private Customer newCustomer;
// Code omitted for clarity..
public void CreateCustomer()
{
newLocation = new Location();
newArea = new Area{Location = newLocation};
newAddress = new Address{Area = newArea};
newCustomer = new Customer{Address = newAddress};
}
凡位置,面积,地址和客户是参考ADO.net EF模型类。然后到newLocation和newArea被修改,当用户在ComboBox选择从一个列表中的位置或区域,像这样:
private Location _selectedLocation;
public Location SelectedLocation
{
get { return _selectedLocation; }
set {
_selectedLocation = value;
newLocation = _selectedLocation;
}
}
SelectedLocation是绑定到位置组合框的组合框的SelectedItem数据。 newArea发生类似的过程。
当用户点击保存会发生以下情况:
public bool SaveCustomer(Customer customer)
{
if(customer == null) return false;
var dataService = new DataService.DataServiceClient();
try
{
if (customer.ID > 0) dataService.UpdateCustomer(customer);
else dataService.CreateCustomer(customer);
}
catch (Exception e)
{
Trace.WriteLine(e.Message);
return false;
}
return true;
}
被调用的数据服务是像这样的方法。
/// <summary>
/// The create.
/// </summary>
/// <param name="customer">
/// The customer.
/// </param>
public static bool Create(Customer customer)
{
if (customer== null) return false;
// Once again, a new instance of the Context..
using (var context = new CustomerDataEntities())
{
try
{
context.AddToCustomerSet(customer);
context.SaveChanges();
}
catch (Exception e)
{
return false;
}
return true;
}
}
的问题
这将引发错误:
The object cannot be added to the ObjectStateManager because it already has an EntityKey. Use ObjectContext.Attach to attach an object that has an existing key.
这是因为Customer.Address.Area
的背景下,已经存在,并且其要求我使用context.Attach()
第一。我试过context.Attach()无济于事。我应该采取什么方法来解决这个问题?
与其试图针对这个问题的具体解决方案,我会敦促您为ObjectContexts的生命周期提出一个通用策略。我不能给你一个这样的“最佳实践”,因为它取决于你的应用程序。例如,我主要做ASP.NET MVC应用程序,所以我的ObjectContexts的生命周期始终是一个持续一个请求的上下文。
这里的一般问题是,实体框架会期望对象图中的任何对象(换句话说,直接或直接相互引用的对象)将成为单个ObjectContext的一部分。如果,例如,您有一个称为区域的对象,其连接到某个ObjectContext的和不附加任何ObjectContext的(换句话说,它是分离的)一个对象调用的客户,并更改客户,使其间接指通过地址的区域,然后如果你看看客户的EntityState,你会看到它现在被“添加”了。试图通过AddToCustomerSet将其添加到不同的ObjectContext将会抛出您报告的错误,因为实体不能存在于两个ObjectContext中。另一方面,在前一个上下文中调用SaveChanges将导致客户被添加到数据库中,而根本不调用AddToCustomerSet,因为它已隐式添加到集合中。
这可能听起来很复杂,或难以管理。但是你会发现,如果你能找到一种方法来使用一个ObjectContext,几乎所有的复杂事件都会消失。没有规则禁止使用多个ObjectContext,但是如果您是Entity Framework的新手,我会敦促您在稍后使用EF的时候不要这样做。
再次感谢克雷格,这绝对是我需要的那种方向。我也从CodeProject http://www.codeproject.com/KB/architecture/attachobjectgraph.aspx找到了这个问题的解决方案。这解决了尝试使用混用的Attached和Detached对象相互引用来添加/修改数据的问题。 – 2009-10-22 23:08:09
请编辑您的问题,包括确切的错误信息。我怀疑你使用了两种不同的上下文,这通常是一个错误。 – 2009-10-21 13:01:12
克雷格,我确实使用了多种不同的上下文。这是因为我通过WCF数据服务访问数据。我已经用更多的细节编辑了这个问题,所以你可以看到我出错的地方。 PS。我对ADO.net EF非常感兴趣,所以感谢您的耐心等待。 – 2009-10-21 23:04:20