将DataGrid绑定到EntitySet

时间:2013-11-28 22:06:24

标签: c# wpf linq-to-sql datagrid one-to-many

在这个例子中,我有一个可以拥有许多PhoneNumbers的Customer。这些是对象:

客户

[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>(); }
}

和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-EL78137MUMS\SQLEXPRESS;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>

很抱歉很长的介绍,这是我的问题以及一些问题 - 当我尝试在网格中添加新的电话号码并调用db.SubmitChanges()时,我收到以下错误消息:“尝试了删除Customer和PhoneNumber之间的关系。但是,其中一个关系的外键(PhoneNumber.CustomerId)不能设置为null。“现在我不希望用户在需要添加电话号码时不断写入客户的ID,因为已经选择了正确的客户并且我正在尝试在他的数字集合中添加另一个号码。如何/应该如何做? 其他问题是:

  1. 看起来在按下Enter之前不会添加新行,如果我输入电话号码,然后在点击调用db.SubmitChanges()的按钮后,就不会发生任何事情(所有三个集合[insert /更新/删除]将为空)。
  2. 我是否必须在PhoneNumber中持有EntityRef?在野外有很多没有它的例子,有些人把它称为一对一连接实用程序。
  3. 无论哪种方式,将EntityRef定义为IsForeignKey = true对我来说有点奇怪,我觉得PhoneNumber.CustomerId应定义为ForeignKey更合理,但当我尝试用[Association]标记它时(IsForeignKey = true,Name =“FK_AddressBook_Customers”,ThisKey =“CustomerId”,OtherKey =“Id”)]我在应用程序启动时收到此错误“无法在类型'字符串上找到键'Id'的关键成员'Id' '。键可能是错的,或'String'上的字段或属性已更改名称“。我没有在互联网上找到任何有用的东西。它应该以另一种方式标记吗?它应该被标记吗?
  4. 我是否必须(或者我应该?)使用一个名称从两端(EntitySet和EntityRef)命名外键(就像我在另一个例子中看到的那样,并且在这里以相同的方式完成)?

1 个答案:

答案 0 :(得分:0)

嗯,主要问题的答案很简单,在PhoneNumber in Association属性中我忘记了存储属性。正确的属性定义如下:

[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将它们命名为完全相同)。请再说一遍。