在这个例子中,我有一个客户,它可以有很多电话号码。这些是对象:
客户
[Table(Name = "Customers")]
public class Customer : INotifyPropertyChanged
{
private String id;
private String givenName;
private String surname;
private EntitySet<PhoneNumber> phoneNumbers;
//INotifyPropertyChanged implementation was elided...
[Column(IsPrimaryKey=true, Storage="id", Name="Id", DbType="NVarChar(10) NOT NULL", CanBeNull=false)]
public String Id
{
get { return this.id; }
set
{
if (this.id != value)
{
this.id = value;
this.OnPropertyChanged("Id");
}
}
}
[Column(Storage="givenName", Name="GivenName", DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
public String GivenName
{
get { return this.givenName; }
set
{
if (this.givenName != value)
{
this.givenName = value;
this.OnPropertyChanged("GivenName");
}
}
}
[Column(Storage="surname", Name="Surname", DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
public String Surname
{
get { return this.surname; }
set
{
if (this.surname != value)
{
this.surname = value;
this.OnPropertyChanged("Surname");
}
}
}
[Association(Name="FK_PhoneBook_Customers", Storage = "phoneNumbers", ThisKey="Id", OtherKey = "CustomerId")]
public EntitySet<PhoneNumber> PhoneNumbers
{
get
{
return this.phoneNumbers;
}
set
{
if (this.phoneNumbers!= value)
{
this.phoneNumbers.Assign(value);
this.OnPropertyChanged("PhoneNumbers");
}
}
}
public Customer() { this.phoneNumbers = new EntitySet<PhoneNumber>(); }
}
和电话号码
[Table(Name = "PhoneBook")]
public class PhoneNumber: INotifyPropertyChanged
{
private int id;
private String customerId;
private String number;
private EntityRef<Customer> customer;
//INotifyPropertyChanged implementation was elided...
[Column(IsPrimaryKey=true, IsDbGenerated=true, Storage="id", Name="Id", DbType="int", CanBeNull=false)]
public int Id
{
get { return this.id; }
private set
{
if (this.id != value)
{
this.id = value;
this.OnPropertyChanged("Id");
}
}
}
[Column(Storage="customerId", Name="CustomerId", DbType="NVarChar(10) NOT NULL", CanBeNull=false)]
public String CustomerId
{
get { return this.customerId; }
set
{
if (this.customerId != value)
{
this.customerId = value;
this.OnPropertyChanged("CustomerId");
}
}
}
[Column(Storage="number", Name="Number", DbType="NVarChar(10) NOT NULL", CanBeNull=false)]
public String Number
{
get { return this.number; }
set
{
if (this.number != value)
{
this.number = value;
this.OnPropertyChanged("Number");
}
}
}
[Association(IsForeignKey=true, Name="FK_PhoneBook_Customers", ThisKey="CustomerId", OtherKey = "Id")]
public Customer Customer
{
get { return this.customer.Entity; }
set { this.customer.Entity = value; }
}
public PhoneNumber() { this.customer = new EntityRef<Customer>(); }
}
我创建了一个DataContext并得到了一个客户(简化版):
db = new DataContext(@"server=WIN-EL78137MUMSSQLEXPRESS;database=SandBox;integrated security=SSPI");
// Get a typed table to run queries.
customers = db.GetTable<Customer>();
custQuery =
from cust in customers
orderby cust.Id
select cust;
Customer = custQuery.Skip(5).Take(1).First();
我在XAML中添加了DataGrid,并将其绑定到Customer的PhoneNumbers属性。
<DataGrid ItemsSource="{Binding PhoneNumbers}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Id, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="CustomerId" Binding="{Binding CustomerId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Number" Binding="{Binding Number, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>
很抱歉介绍太长了,这是我的问题和一些问题——当我试图在网格中添加一个新的电话号码并拨打数据库时。SubmitChanges()我收到以下错误消息:"试图删除Customer和PhoneNumber之间的关系。但是,该关系的外键之一(PhoneNumber.CustomerId)不能设置为null。"。现在,我不希望用户在需要添加电话号码时不断写入客户的id,因为已经选择了合适的客户,我正试图将另一个号码添加到他的号码集合中。这该怎么做
其他问题包括:
- 如果我输入电话号码,然后点击一个调用db的按钮,那么在按下Enter键之前,似乎不会添加新行。SubmitChanges(),则不会发生任何事情(所有三个集合[intert/update/delete]都将为空)
- 我必须在PhoneNumber中持有EntityRef吗?在野外有很多例子根本没有它,有些人提到它是一对一连接实用程序
- 无论哪种方式,将EntityRef定义为IsForeignKey=true对我来说都有点奇怪,PhoneNumber.CustomerId应该定义为ForeignKey对我来说更合理,但当我尝试用[Association(IsForeignKey=true,Name="FK_AddressBook_Customers",ThisKey="CustomerId",OtherKey="Id")]标记它时,我在应用程序启动时遇到了此错误"在类型"String"上找不到键"Id"的键成员"Id"。该键可能错误,或者"String"的字段或属性已更改名称"。我在网上找不到任何有用的东西。它应该用另一种方式标记吗?它应该被标记吗
- 我是否必须(或者应该?)用一个名称从两端(EntitySet和EntityRef)命名外键(就像我在另一个例子中看到的那样,在这里也是这样做的)
好吧,主要问题的答案很简单,在Association属性中的PhoneNumber中,我忘记了Storage属性。正确的属性定义如下:
[Association(IsForeignKey=true, Name="FK_PhoneBook_Customers", Storage="customer", ThisKey="CustomerId", OtherKey = "Id")]
public Customer Customer
{
get { return this.customer.Entity; }
set { this.customer.Entity = value; }
}
第二个问题的答案是"不",事实上,如果没有它,我根本不会面临主要问题。但由于某些原因,Visual Studio创建了此反向引用。如果你们中有人知道为什么它会有用,请分享你们的想法
第三个问题的答案也是"不,它根本不应该被标记"。在PhoneNumber.CustomerId属性没有附加任何关联属性的情况下,一切都开始工作,这一点就变得显而易见了
对于第四个问题,我也得到了部分答案——"不,我不必从两端给出相同的名字——它将继续使用不同的名字。",但可能是因为一些未知和不必要的后果,我应该给出相同的名称(再次,VS对它们的命名完全相同)。请再次提出建议。