如何在代码中建立多对多的关系模型?

时间:2017-03-03 07:11:14

标签: c# model

我在C#系统中工作,我需要建模多对多关系,我想手动构建模型(即我不想使用任何框架)。

我将通过一个简化的系统示例,然后解释问题: 我有一个包含 Book 作者的库,每个 Book 可以有很多作者,同样的适用于作者

public class Book{
     public string Title;
     public List<Author> Authors;
}

public class Author{
     public string Name;
     public List<Book> Books;
 }

现在,如果我想与所有作者一起 SELECT 书籍;我会在 Book 的类中编写一个函数,如下所示:

public List<Book> All(){
     List<Book> Books = new List<Book>();
     Books = //Query that brings all books and its Authors and populate them into the Books list.   
 }

现在我应该可以这样做:

 Book boo = new Book();
 List<Book> books = boo.All();
 Console.WriteLine(books[0].Authors[0].Name);

但我不能做的是:

 Console.WriteLine(books[0].Authors[0].Books[0].Title);

因为在此流程中books[0].Authors[0].Books[0]将为null(或默认值)。 所以我不会做一些半动态的东西,并且仍然记住表现 数据库服务器和客户端服务器透视图。

希望我明白我的观点。谢谢你的时间。

3 个答案:

答案 0 :(得分:0)

我会做这样的事情来模仿数据库n到n的关系:

    public class DB
    {
        public class Book
        {
            public string Title;

            public List<Author> Authors
            {
                get
                {
                    return
                        BookAuthor.Connection.Where(ba => ba.Book.Title == this.Title)
                            .Select(ba => ba.Author)
                            .ToList();
                }
            }

            public void AddAuthor(Author a)
            {
                var connection = new BookAuthor(this, a);

                if (!BookAuthor.Connection.Exists(c => c.Author.Name == connection.Author.Name &&
                                                      c.Book.Title == connection.Book.Title))
                    BookAuthor.Connection.Add(connection);
            }
        }

        public class Author
        {
            public string Name;

            public List<Book> Books
            {
                get
                {
                    return
                        BookAuthor.Connection.Where(ba => ba.Author.Name == this.Name)
                            .Select(ba => ba.Book)
                            .ToList();
                }
            }

            public void AddBook(Book b)
            {
                var connection = new BookAuthor(b, this);

                if (!BookAuthor.Connection.Exists(c => c.Author.Name == connection.Author.Name &&
                                                      c.Book.Title == connection.Book.Title))
                    BookAuthor.Connection.Add(connection);
            }
        }

        private class BookAuthor
        {
            public Book Book { get; set; }
            public Author Author { get; set; }

            public static List<BookAuthor> Connection { get; } = new List<BookAuthor>();

            public BookAuthor(Book book, Author author)
            {
                Book = book;
                Author = author;
            }
        }
    }

    public void Run()
    {
        List<DB.Book> books = new List<DB.Book>()
        {
            new DB.Book() {Title = "Crime & Punishment"},
            new DB.Book() {Title = "Karamazov"}
        };

        List<DB.Author> authors = new List<DB.Author>()
        {
            new DB.Author()
            {
                Name = "Dostoyevsky",
                Books = { books[0] }
            }
        };
        authors[0].AddBook(books[1]);
        authors[0].AddBook(books[1]); // constraint

        List<DB.Book> allBooksOfDostoyevsky = authors[0].Books;
        var dost = authors[0].Books[0].Authors[0].Name; // Dostoyevsky
    }

答案 1 :(得分:0)

在传统的数据库设计中,n:m关系由三个表组成:

Author -- 1:n --> helper table <-- n:1 -- Book

这就是我要做的,有3个班级,书籍,作者和连接两者的东西:

class Book {
    public int ID { get; set; }
    public string Title { get; set; }
}

class Author {
    public int ID { get; set; }
    public string Name { get; set; }
}

class BookAuthorConnections {
    public int ID_Book { get; set; }
    public int ID_Author { get; set; }
}

...然后制作包含这些类的3个列表,例如:

static void Main(string[] args) {
    var authors = new List<Author>() {
        new Author() { ID = 1, Name = "Blah" },
        new Author() { ID= 2, Name = "Blubb" }
    };
    var books = new List<Book>() {
        new Book() { ID = 1, Title = "Some Book" },
        new Book() { ID = 2, Title = "Some other Book"},
        new Book() { ID = 3, Title = "Book 3"}
    };
    var connections = new List<BookAuthorConnections> {
        new BookAuthorConnections() { ID_Author = 1, ID_Book = 1 },
        new BookAuthorConnections() { ID_Author = 1, ID_Book = 2 },
        new BookAuthorConnections() { ID_Author = 2, ID_Book = 2 },
        new BookAuthorConnections() { ID_Author = 2, ID_Book = 3 }
    };

...然后加入他们,关于作者关系的书籍。使用简单的Where,您可以访问所需的一切:

var result = books
    .Join(connections, book => book.ID, connection => connection.ID_Book, (book, con) => new { book.Title, con.ID_Author, con.ID_Book })
    .Join(authors, temp_result => temp_result.ID_Author, author => author.ID, (temp_result, author) => new { author.Name, temp_result.Title, temp_result.ID_Author, temp_result.ID_Book })
    .Where(x => x.Title == "Some other Book"); //returns all authors who wrote that book
    //.Where(x => x.Author == "...") would return all Books written by that author
    //.Where(x => x.ID_Book .... or x.ID_Author would access everything by ID

答案 2 :(得分:0)

Author类直接向上(在构造函数中填充它):

公共课作者 {         公共作者(字符串名称)         {             名字=姓名;             Books = new List();         }         public string Name {get;组; }         公共列表簿{get;组; }     }

Book类中,我也填充了构造函数。作为一种扭曲,我将每个Author的书籍属性设置为this

  public class Book
    {
        public Book(string name, IList<Author> authors)
        {
            Name = name;
            Authors = new List<Author>();
            foreach (Author author in authors)
            {
                author.Books.Add(this);
                Authors.Add(author);
            }
        }

        public string Name { get; set; }
        public List<Author> Authors { get; set; }
    }

代码将类似于:

    public void main()
    {
        Author hermanM = new Author("Herman Melville");

        IList<Author> authors = new List<Author>();
        authors.Add(hermanM);

        Book mobyDick = new Book("Moby-Dick",authors);


        string bookTitle = mobyDick.Authors[0].Books[0].Name;

    }

任何像这样创建的书都可以通过linq查询选择,或者你想要这样做。此外,链条将是无限的。在这种情况下,我可以选择标题。来自:

string bookTitle = mobyDick.Name;

但我也可以把它拉到其他水平,比如:

string bookTitle = mobyDick.Authors[0].Books[0].Authors[0].Books[0].Authors[0].Books[0]; 

在这种情况下,只有一本书由一位作者撰写,结果将是相同的。

在下面的示例中。我创建了一个有两本书的图书馆。然后我搜索作者的书籍。

public void BooksByAuthorExample()
    {

    //Create library 
    IList<Book> myLibrary = new List<Book>();

    //Define first book
    Author hermanM = new Author("Herman Melville");

    IList<Author> authors = new List<Author>();
    authors.Add(hermanM);

    Book mobyDick = new Book("Moby-Dick", authors);



    //Define second book
    Author gamma = new Author("Eric Gamma");
    Author helm = new Author("Richard Helm");
    Author johnson = new Author("Ralph Johnson");
    Author vlissides = new Author("Johm Vlissides");
    IList<Author> gangOfFour = new List<Author>() { gamma, helm, johnson, vlissides};
    Book designPatterns = new Book("Design Patterns - Elements of Reusable Object-Oriented Software", gangOfFour);


    //Add books to the library 
    myLibrary.Add(mobyDick);
    myLibrary.Add(designPatterns);

    //Select books written by Richard Helm

    IList<Book> searchResult = myLibrary.Where(x => x.Authors.Contains(helm)).ToList();
}