none
Отображение в DataGrid информации по связям RRS feed

  • Вопрос

  • Здравствуйте еще раз. Снова с вопросами.

    Есть база данных с такой структурой:

    namespace Library_Manager
    {
        public class LM : DataContext
        {
            public Table<Book> Books;
            public Table<TakeBook> TakeBooks;
            public Table<User> Users;
    
            public LM(string connection) : base(connection) { }
        }
    
        [Table(Name = "Books")]
        public class Book
        {
            private int _BookID = 1;    //столбец идентификатора
            private string _BookName;   //столбец имени книги
    
            [Column(Storage = "_BookID", IsPrimaryKey = true, CanBeNull = false, DbType = "Int NOT NULL IDENTITY", IsDbGenerated = true)]
            public int PK_BookID
            {
                get { return this._BookID; }
            }
    
            [Column(Storage = "_BookName")]
            public string BookName
            {
                get { return this._BookName; }
                set { this._BookName = value; }
            }
        }
    
        [Table(Name = "TakeBooks")]
        public class TakeBook
        {
            private int _TBID = 1;
            private EntityRef<Book> _Book;
            private EntityRef<User> _User;
            private DateTimeOffset _TakeDate;
            private DateTimeOffset _ReturnDate;
    
            public TakeBook()
            {
                this._Book = new EntityRef<Book>();
                this._User = new EntityRef<User>();
            }
    
            [Column(Storage = "_TBID", IsPrimaryKey = true, CanBeNull = false, DbType = "Int NOT NULL IDENTITY", IsDbGenerated = true)]
            public int PK_TBID
            {
                get { return this._TBID; }
            }
    
            [Column(Storage = "_TakeDate")]
            public DateTimeOffset TakeDate
            {
                get { return this._TakeDate; }
                set { this._TakeDate = value; }
            }
    
            [Column(Storage = "_ReturnDate")]
            public DateTimeOffset ReturnDate
            {
                get { return this._ReturnDate; }
                set { this._ReturnDate = value; }
            }
    
            //внешний ключ, указывающий на Books.BookID
            [Association(Storage = "_Book", ThisKey = "BookID", IsForeignKey = true)]
            public Book FK_Book
            {
                get { return this._Book.Entity; }
                set { this._Book.Entity = value; }
            }
    
            //внешний ключ, указывающий на Users.UserID
            [Association(Storage = "_User", ThisKey = "UserID", IsForeignKey = true)]
            public User FK_User
            {
                get { return this._User.Entity; }
                set { this._User.Entity = value; }
            }
        }
    
        //сущность таблицы Users
        [Table(Name = "Users")]
        public class User
        {
            private int _UserID = 1;
            private string _UserName;
            private string _UserFamily;
    
            [Column(IsPrimaryKey = true, Storage = "_UserID", CanBeNull = false, DbType = "Int NOT NULL IDENTITY", IsDbGenerated = true)]
            public int PK_UserID
            {
                get { return this._UserID; }
                //set не нужен, т.к. св-во уникальное
            }
    
            [Column(Storage = "_UserName")]
            string UserName
            {
                get { return this._UserName; }
                set { this._UserName = value; }
            }
    
            [Column(Storage = "_UserFamily")]
            string Family
            {
                get { return this._UserFamily; }
                set { this._UserFamily = value; }
            }
        }
    }

    И есть DataGrid, в который данные передаются вот так вот:

    main.DataView.DataContext = db.TakeBooks.ToList();

    Вопрос вот в чем:

    Как в DataGrid отобразить информацию из связанной таблицы? Например из TakeBooks.FK_Book.BookName. ?

    Пробовал как нибудь так, но то ли лыжи не те, то ли я...

    <DataGrid ItemsSource="{Binding}" ColumnWidth="*" AutoGenerateColumns="False" Margin="0,31,0,0" x:Name="DataView" MouseDoubleClick="DataView_MouseDoubleClick">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Абонемент" Binding="{Binding PK_UserID}" />
                    <DataGridTextColumn Header="Имя" Binding="{Binding FK_UserID.UserName}" />
                    <DataGridTextColumn Header="Фамилия" Binding="{Binding FK_UserUD.UserFamily}" />
                    <DataGridTextColumn Header="Взятая книга" Binding="{Binding FK_Book.BookName}" />
                    <DataGridTextColumn Header="Дата взятия" Binding="{Binding TakeDate}" />
                    <DataGridTextColumn Header="Дата возврата" Binding="{Binding ReturnDate}" />
                </DataGrid.Columns>
            </DataGrid>


    MSDN AA User

    27 апреля 2012 г. 14:10

Ответы

  • У вас есть Navigation Property (те что без ID в названии) и поля для мапинга ключей в базе данных (c ID в названии), так вот, у олей с ID в названии - свойств нет. Они типа int. Поэтому в биндинге надо использоваать поля без ID:

    <DataGrid ItemsSource="{Binding}" ColumnWidth="*" AutoGenerateColumns="False" Margin="0,31,0,0" x:Name="DataView" MouseDoubleClick="DataView_MouseDoubleClick">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Абонемент" Binding="{Binding PK_UserID}" />
                    <DataGridTextColumn Header="Имя" Binding="{Binding FK_User.UserName}" />
                    <DataGridTextColumn Header="Фамилия" Binding="{Binding FK_User.UserFamily}" />
                    <DataGridTextColumn Header="Взятая книга" Binding="{Binding FK_Book.BookName}" />
                    <DataGridTextColumn Header="Дата взятия" Binding="{Binding TakeDate}" />
                    <DataGridTextColumn Header="Дата возврата" Binding="{Binding ReturnDate}" />
                </DataGrid.Columns>
            </DataGrid>


    27 апреля 2012 г. 16:27
    Отвечающий
  • Объясняю:

    1. Данные хранятся в базе данных. Современные базы данных реляционные. Т.е. для связи двух сущностей в отношении один ко многим нам необходим в главной сущности (та которая один) использовать первичный ключ, в дочерней сущности (та где много) используется внешний ключ. Поэтому если вам нужно из дочерней таблицы выбрать данные которые ассоциированы с сущностью в главной у которой первичный ключ равен 5, вы пишите вот такой запрос:

    select * from Children where FK_ParentID = 5

    2. Entity Model это так называемый объектно-реляционный мапинг (ORM). Т.е. в базе у вас лежат сущности в виде таблиц со связями между ними. В Entity Model эти таблицы преобразуются в классы. И у вас для полей из БД появляются поля в классах. Но, в БД есть еще и связи. Таблица Parents связана один ко многим с таблицей Children. И вот тут начинается магия. Для реализации этой связи в модель добавляются два Navigation Property, в класс Parent добавляется поле Children (множественное число, т.к. 1 паренту соответствует много деток), а в класс Child добавляется поле Parent (т.к. у каждой детки всего 1 парент). В базе данных таких полей нет, но они вам позволяют имея ссылку на один из объектов получать все связанные с ним объекты из других сущностей через Navigation Property.

    Parent p = // Инициализация при помощи Linq
    MessageBox.Show(p.Children[0].Name);

    28 апреля 2012 г. 3:28
    Отвечающий

Все ответы

  • У вас есть Navigation Property (те что без ID в названии) и поля для мапинга ключей в базе данных (c ID в названии), так вот, у олей с ID в названии - свойств нет. Они типа int. Поэтому в биндинге надо использоваать поля без ID:

    <DataGrid ItemsSource="{Binding}" ColumnWidth="*" AutoGenerateColumns="False" Margin="0,31,0,0" x:Name="DataView" MouseDoubleClick="DataView_MouseDoubleClick">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Абонемент" Binding="{Binding PK_UserID}" />
                    <DataGridTextColumn Header="Имя" Binding="{Binding FK_User.UserName}" />
                    <DataGridTextColumn Header="Фамилия" Binding="{Binding FK_User.UserFamily}" />
                    <DataGridTextColumn Header="Взятая книга" Binding="{Binding FK_Book.BookName}" />
                    <DataGridTextColumn Header="Дата взятия" Binding="{Binding TakeDate}" />
                    <DataGridTextColumn Header="Дата возврата" Binding="{Binding ReturnDate}" />
                </DataGrid.Columns>
            </DataGrid>


    27 апреля 2012 г. 16:27
    Отвечающий
  • У вас есть Navigation Property (те что без ID в названии) и поля для мапинга ключей в базе данных (c ID в названии), так вот, у ID свойств нет. Они типа int. Поэтому в биндинге надо использоваать поля без ID:

    <DataGrid ItemsSource="{Binding}" ColumnWidth="*" AutoGenerateColumns="False" Margin="0,31,0,0" x:Name="DataView" MouseDoubleClick="DataView_MouseDoubleClick">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Абонемент" Binding="{Binding PK_UserID}" />
                    <DataGridTextColumn Header="Имя" Binding="{Binding FK_User.UserName}" />
                    <DataGridTextColumn Header="Фамилия" Binding="{Binding FK_User.UserFamily}" />
                    <DataGridTextColumn Header="Взятая книга" Binding="{Binding FK_Book.BookName}" />
                    <DataGridTextColumn Header="Дата взятия" Binding="{Binding TakeDate}" />
                    <DataGridTextColumn Header="Дата возврата" Binding="{Binding ReturnDate}" />
                </DataGrid.Columns>
            </DataGrid>
    Щас попробую, а пока что можете объяснить более простым языком то, что Вы написали перед примером кода? :)

    MSDN AA User


    27 апреля 2012 г. 16:42
  • Объясняю:

    1. Данные хранятся в базе данных. Современные базы данных реляционные. Т.е. для связи двух сущностей в отношении один ко многим нам необходим в главной сущности (та которая один) использовать первичный ключ, в дочерней сущности (та где много) используется внешний ключ. Поэтому если вам нужно из дочерней таблицы выбрать данные которые ассоциированы с сущностью в главной у которой первичный ключ равен 5, вы пишите вот такой запрос:

    select * from Children where FK_ParentID = 5

    2. Entity Model это так называемый объектно-реляционный мапинг (ORM). Т.е. в базе у вас лежат сущности в виде таблиц со связями между ними. В Entity Model эти таблицы преобразуются в классы. И у вас для полей из БД появляются поля в классах. Но, в БД есть еще и связи. Таблица Parents связана один ко многим с таблицей Children. И вот тут начинается магия. Для реализации этой связи в модель добавляются два Navigation Property, в класс Parent добавляется поле Children (множественное число, т.к. 1 паренту соответствует много деток), а в класс Child добавляется поле Parent (т.к. у каждой детки всего 1 парент). В базе данных таких полей нет, но они вам позволяют имея ссылку на один из объектов получать все связанные с ним объекты из других сущностей через Navigation Property.

    Parent p = // Инициализация при помощи Linq
    MessageBox.Show(p.Children[0].Name);

    28 апреля 2012 г. 3:28
    Отвечающий