繁体   English   中英

Entity Framework Core 2.1 的关系问题

[英]Entity Framework Core 2.1 trouble with relationships

我正在尝试将以下 sql 查询转换为实体框架,但遇到列未加入表的问题。

SELECT 
a.TABLE_NAME AS tableName,
b.COLUMN_NAME AS columnName,
b.DATA_TYPE AS dataType,
CASE WHEN b.IS_NULLABLE = 'NO' THEN 'FALSE' ELSE 'TRUE' END AS allowNull
FROM INFORMATION_SCHEMA.TABLES a
INNER JOIN INFORMATION_SCHEMA.COLUMNS b ON a.TABLE_NAME = b.TABLE_NAME

这是我到目前为止

数据库上下文:

using Microsoft.EntityFrameworkCore;

namespace EFCoreTest.Models 
{
    public class InformationContext : DbContext
    {   
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 
        {
            optionsBuilder.UseSqlServer(@"Server=localhost;Database=master;Trusted_Connection=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Table>()
                .HasKey(t => new {t.tableName, t.catalogName, t.schemaName});

            modelBuilder.Entity<Column>()
                .HasOne(c => c.table)
                .WithMany(c => c.columns)
                .HasForeignKey(c => new {c.tableName, c.catalogName, c.schemaName});

        }

        public DbSet<Table> Tables {get; set;}
        public DbSet<Column> Columns {get; set;}
    }
}

列类:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace EFCoreTest.Models
{
    [Table("COLUMNS", Schema = "INFORMATION_SCHEMA")]
    public class Column
    {
        [Key]
        [Column("COLUMN_NAME")]
        public String columnName {get; set;}
        [Column("DATA_TYPE")]
        public String dataType {get; set;}
        [Column("IS_NULLABLE")]
        public String allowNUlls {get; set;}
        [ForeignKey("Table")]
        [Column("TABLE_NAME")]
        public String tableName {get; set;}
        [ForeignKey("Table")]
        [Column("TABLE_CATALOG")]
        public String catalogName {get; set;}
        [ForeignKey("Table")]
        [Column("TABLE_SCHEMA")]
        public String schemaName {get; set;}
        public Table table {get; set;}

    }
}

表类:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace EFCoreTest.Models
{
    [Table("TABLES" , Schema = "INFORMATION_SCHEMA")]
    public class Table
    {
        [Key]
        [Column("TABLE_NAME")]
        public String tableName {get; set;}
        [Key]
        [Column("TABLE_CATALOG")]
        public String catalogName {get; set;}
        [Key]
        [Column("TABLE_SCHEMA")]
        public String schemaName {get; set;}
        public ICollection<Column> columns {get; set;}

        protected Table() {columns = new List<Column>();}
    }
}

主要的:

using System;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using EFCoreTest.Models;

namespace EFCoreTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using(InformationContext context = new InformationContext())
            {
                var results = context.Tables.Include(t => t.columns).ToList();

                foreach(var t in results)
                {
                    Console.WriteLine(t.tableName);
                    Console.WriteLine("-----------------------------");
                    var columns = t.columns.ToList();

                    foreach(var c in columns)
                    {
                        Console.WriteLine(c.columnName);
                    }

                    Console.WriteLine("");
                }
            }
        }
    }
}

代码运行良好,但在检查表实例时,所有列实例都为空。 我有一种感觉,它与表和列之间的关系有关,但在查看了 efcore2.1 关系的文档后,我无法弄清楚我做错了什么。

任何帮助,将不胜感激。

更新:使用附加键和相关数据加载更新代码。

尝试这个:

context.Tables.Include(t => t.columns).ToList();

首先,欢迎堆栈溢出。

根据 Gonzalo 的回答,Include 语句将让您包含一个集合:

context.Tables.Include(t => t.columns).ToList();

然而,我想强调一些其他小的改进,您可以做一些其他的小改进,使您的代码随着时间的推移变得更加健壮和可维护。

  1. 请记住使用受保护的构造函数初始化您的实体以避免空指针异常,因为在大多数情况下,返回带有实体的空集合应该是业务应用程序的有效场景:

    受保护的表(){列=新列表(); }

  2. 使用 ICollection 而不是 List 来定义集合。

  3. C# 中的通用命名标准是在声明公共属性和集合时使用 Pascal 大小写。

  4. 您正在混合两种定义关系的不同方式。

这个:

modelBuilder.Entity<Column>()
    .HasOne(c => c.table)
    .WithMany(c => c.columns)
    .HasForeignKey(c => c.tableForeignKey);

而你在实体的相关属性上使用的注解,比如 [Key] 实际上是两种不同的方式来做同样的事情。 首先使用一个,最好是代码,即通过配置。

5、我建议使用单独的实体类型配置文件,否则你的架构最终将很难维护,例如基本配置:

public class BaseEntityConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
    where TEntity : BaseEntity
{
    public virtual void Configure(EntityTypeBuilder<TEntity> builder)
    {
        builder.HasKey(be => be.Guid);

        builder.Property(be => be.CreatedBy).IsRequired();

        builder.Property(be => be.CreatedDate).IsRequired();
    }
}

public class AddressConfiguration : BaseEntityConfiguration<Address>
{
    public override void Configure(EntityTypeBuilder<Address> builder)
    {
        builder.HasOne(a => a.Contact)
            .WithMany(c => c.Addresses)
            .HasForeignKey(a => a.ContactGuid);

        builder.HasOne(a => a.Partner)
            .WithMany(a => a.Addresses)
            .HasForeignKey(a => a.PartnerGuid);

        base.Configure(builder);
    }
}

并在上下文中:

modelBuilder.ApplyConfiguration(new AddressConfiguration());

正如您可能注意到的那样,我还使用 BaseEntity 来保存所有重复属性,例如 Id,并从中派生出我的所有实体。 我建议你也这样做。

希望有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM