EF核心 - 多对多关系不起作用

时间:2018-03-02 10:13:11

标签: .net-core entity-framework-core

我在尝试使用EF Core 2.0中的多对多关系时遇到了一些问题。这是我的代码:

以下是我的实体: 用户

 public class User : IdentityUser
{
    private User()
    {
    }

    public String Name { get; private set; }
    public ICollection<UserCourse> UserCourses { get; private set; }

    public static User Create(string name, string username, string email)
    {
        var instance = new User
        {
            Id = Guid.NewGuid().ToString(),

        };
        instance.Update(name, username, email);
        return instance;
    }

    public void Update(string name, string username, string email)
    {
        Name = name;
        UserName = username;
        Email = email;
    }

    public void Update(UserCreatingModel model)
    {
        this.UserName = model.Username;

        this.Name = model.Name;

        this.Email = model.Email;
    }

    public void Update(UserCourse userCourse)
    {
        if (UserCourses == null)
        {
            UserCourses = new List<UserCourse>() {userCourse};
        }
        else
        {
            UserCourses.Add(userCourse);
        }
    }
}

课程实体

 public class Course
{
    private Course() { }

    public Guid Id { get; private set; }
    public string Name { get; private set; }
    public int Year { get; private set; }
    public int Semester { get; private set; }
    public List<Lesson> Lessons { get; private set; }
    public ICollection<UserCourse> UserCourses { get; private set; }

    public static Course Create(string name, int year, int semester, List<Lesson> lessons, List<User> professors)
    {
        var instance = new Course { Id = Guid.NewGuid() };
        instance.Update(name, year, semester, lessons);
        return instance;
    }

    public static Course Create(string name, int year, int semester)
    {
        var instance = new Course { Id = Guid.NewGuid() };
        instance.Update(name, year, semester);
        return instance;
    }



    public void Update(string name, int year, int semester, List<Lesson> lessons)
    {
        Name = name;
        Year = year;
        Semester = semester;
        Lessons = lessons;
    }
    public void Update(string name, int year, int semester)
    {
        Name = name;
        Year = year;
        Semester = semester;
    }

    public void Update(UserCourse userCourse)
    {
        if (UserCourses == null)
        {
            UserCourses = new List<UserCourse>(){userCourse};
        }
        else
        {
            UserCourses.Add(userCourse);
        }
    }

    public void Update(List<Lesson> lessons)
    {
        this.Lessons = lessons;
    }
}

加入实体

public class UserCourse
{
    private UserCourse() { }

    public string UserId { get; private set; }
    public User User { get; private set; }

    public Guid CourseId { get; private set; }
    public Course Course { get; private set; }

    public static UserCourse CreateUserCourse(string userId, User user, Guid coursId, Course course)
    {
        var instance = new UserCourse
        {
            UserId = userId,
            User = user,
            CourseId = coursId,
            Course = course
        };
        return instance;
    }
}

这是我的数据库上下文

 public sealed class DatabaseContext : IdentityDbContext<User>, IDatabaseContext
{
    public static readonly LoggerFactory MyLoggerFactory
        = new LoggerFactory(new[] {new ConsoleLoggerProvider((_, __) => true, true)});

    public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
    {
        Database.EnsureCreated();
    }


    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseLoggerFactory(MyLoggerFactory) // Warning: Do not create a new ILoggerFactory instance each time
            .EnableSensitiveDataLogging();

    public new DbSet<User> Users { get; set; }
    public DbSet<Course> Courses { get; set; }
    public DbSet<Lesson> Lessons { get; set; }
    public DbSet<UserCourse> UserCourses { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Lesson>()
            .HasOne(p => p.Course)
            .WithMany(b => b.Lessons)
            .OnDelete(DeleteBehavior.Cascade);

        modelBuilder.Entity<UserCourse>()
            .HasKey(uc => new {uc.UserId, uc.CourseId});

        modelBuilder.Entity<UserCourse>()
            .HasOne(uc => uc.User)
            .WithMany(u => u.UserCourses)
            .HasForeignKey(uc => uc.UserId);

        modelBuilder.Entity<UserCourse>()
            .HasOne(uc => uc.Course)
            .WithMany(c => c.UserCourses)
            .HasForeignKey(uc => uc.CourseId);
    }
}

这是我尝试使用方法AddCoursToProfessor

将2个现有实体用户和课程添加到连接表的存储库
public class CoursesRepository : ACrudRepository<Course, Guid>, ICoursesRepository
{
    public CoursesRepository(IDatabaseContext databaseContext) : base(databaseContext)
    {
    }

    public override IReadOnlyList<Course> GetAll() => _databaseContext.Courses.Include(c => c.Lessons).Include(p => p.UserCourses).ToList();

    public override Course GetById(Guid id) 
        => _databaseContext.Courses.Include(c => c.Lessons).AsNoTracking().FirstOrDefault(c => c.Id.Equals(id));

    public void AddCoursToProfessor(string profId, Guid coursId)
    {
        var professor = _databaseContext.Users.Include(u => u.UserCourses).FirstOrDefault(u => u.Id.Equals(profId));
        var course = GetById(coursId);
        var profCourse = UserCourse.CreateUserCourse(profId, professor, coursId, course);

        professor.Update(profCourse);
        _databaseContext.Users.Update(professor);

        _databaseContext.SaveChanges();
    }

}

问题似乎是当尝试添加加入表时,EF尝试再次将课程实体添加到其表中,并且我得到主键冲突错误。我尝试了不同的方法,但似乎都没有。我尝试直接在UserCourse表中添加,但是这会尝试将两个实体添加到他们自己的表中,我尝试在将实体添加到连接表之前删除实体,这也不起作用。如果有人有其他想法,或者处理类似的情况会给你带来很多帮助,我就没有想法了。

我忘了提一下,如果我尝试通过它自己或用户添加一个课程,那将起作用,它们都会被添加到他们的表中,所以我不认为问题出在DB上但是多对多关系的配置

2 个答案:

答案 0 :(得分:0)

据我所知,我是如何实施MTM模式的。

在这种情况下,需要注意3个参数。

CurrencyPairId不是唯一的。它是一个2个独特的参数。 CurrencyId和IsMain是独一无二的。

这是一种交易交易风格的复合键。即EURUSD

EUR =&gt;主对,USD =&gt;对抗。

班级

    /// <summary>
    /// Partial currency pair.
    /// </summary>
    public class PartialCurrencyPair
    {
        public long CurrencyId { get; set; }

        public long CurrencyPairId { get; set; }

        public bool IsMain { get; set; } = false;

        public CurrencyPair CurrencyPair { get; set; }
        public Currency Currency { get; set; }
    }

货币

public class Currency : BaseEntityModel
    {
        [Key]
        public long Id { get; set; }
        public ICollection<PartialCurrencyPair> PartialCurrencyPairs { get; set; }
    }

CurrencyPair

public class CurrencyPair : BaseEntityModel
    {
        [Key]
        public long Id { get; set; }

        // =========== RELATIONS ============ //
        public ICollection<PartialCurrencyPair> PartialCurrencyPairs { get; set; }
    }

一些映射

in Currency;

entity.HasMany(c => c.PartialCurrencyPairs).WithOne(pcp => pcp.Currency).HasForeignKey(pcp => pcp.CurrencyId).OnDelete(DeleteBehavior.Restrict);

在CurrencyPair中

        entity.HasMany(cp => cp.PartialCurrencyPairs).WithOne(pcp => pcp.CurrencyPair).HasForeignKey(pcp => pcp.CurrencyPairId).OnDelete(DeleteBehavior.Restrict);

PartialCurrencyPair

builder.Entity<PartialCurrencyPair>(entity =>
            {
                entity.HasKey(pcp => new { pcp.CurrencyPairId, pcp.IsMain }).HasName("PartialCurrencyPair_CK_CurrencyPairId_IsMain");
            });

根据您的Course.cs判断,UserCourse没有收集,为什么它是静态的?

答案 1 :(得分:0)

好的......所以我最近解决了这个问题。问题是由GetCourseById方法生成的,因为我得到了实体AsNoTracking。该实体不在EF范围内,因此它试图创建它。