具有存储库模式的实体框架,将数据插入到具有多对多关系的表中

Posted

技术标签:

【中文标题】具有存储库模式的实体框架,将数据插入到具有多对多关系的表中【英文标题】:Entity Framework with Repository Pattern, inserting data to tables with many-to-many relationship 【发布时间】:2018-03-05 20:02:58 【问题描述】:

我正在尝试使用 BLL、DAL 和 UI 构建三层架构。我正在做一个小型公寓管理系统项目(其中包括关于住校学生、他们的房间和他们住的房间的公寓的信息)。由于我是初学者,因此我需要解决一些技术问题。我正在使用具有存储库模式的实体框架。我的项目基于MVVM 方法,我正在使用Automapper

Automapper 代码

public class AutoMapperProfile : Profile

    public AutoMapperProfile()
    
        CreateMap<Room, RoomViewModel>().ReverseMap();
        CreateMap<Apartment, ApartmentViewModel>().ReverseMap();
    


public class AutoMapperConfig

    public static void Configure()
    
        Mapper.Initialize(x =>
        
            x.AddProfile<AutoMapperProfile>();
        );
    

我正在尝试向我的数据库中添加一个新房间。我的 Room 和 Apartment 表之间存在多对多关系,我的数据库如下所示:

My Database's screen shot

我的 IRepository 界面如下所示:

public interface IRepository<T> where T : class

    IEnumerable<T> GetAll();
    T GetById(int id);
    T Get(Expression<Func<T, bool>> expression);
    IQueryable<T> GetMany(Expression<Func<T, bool>> expression);
    bool Insert(T obj);
    bool Update(T obj);
    bool Delete(int id);
    int Count();
    void Save();

我有 RoomRepository 和 ApartmentRepository,它们都实现了 IRepository 接口。我已经创建了我的存储库和基础架构:

基础设施(文件夹)

IApartmentRepository.cs IRepository.cs IRoomRepository.cs IStudentRepository.cs IUserRepository.cs

存储库(文件夹)

ApartmentRepository.cs RoomRepository.cs StudentRepository.cs UserRepository.cs

添加新房间时,管理员必须说明该房间属于哪个公寓。 RoomController 中的 Add 方法如下:

[HttpPost]
    public JsonResult Add(RoomViewModel roomModel)
    
        try
        
            //var apartViewModel = new ApartmentRoomViewModel();
            //apartViewModel.ApartmentID = roomModel.ApartmentNameId;
            var room = AutoMapper.Mapper.Map<Room>(roomModel);
            var status = _roomRepository.Insert(room);
            _roomRepository.Save();
            //apartViewModel.RoomID = room.Id;

            return Json(new  status, message = "Ekleme işlemi başarılı." , JsonRequestBehavior.AllowGet);
        
        catch (Exception)
        
            return Json(new  status = false, message = "Hata! Ekleme işlemi gerçekleştirilemedi." , JsonRequestBehavior.AllowGet);
        
    

房间视图模型

 public class RoomViewModel


    public int Id  get; set; 

    public int DoorNumber  get; set; 

    public int FloorNumber  get; set; 

    public int Capacity  get; set; 

    public int Fullness  get; set; 

    public string ApartmentName  get; set; 

    public int ApartmentNameId  get; set; 

用户界面

Room Add UI

我的问题是,当我想在“房间添加”页面中插入从用户那里获取的数据时,我可以将为房间收集的信息添加到房间表中,但我还想添加公寓信息(即那个房间的 ApartmentID)和同一个房间的 RoomID 到数据库中的 ApartmentRoom 表,到目前为止我还不能这样做。如果到目前为止我没有错,那我该怎么办?

    我是否应该创建另一个存储库,例如实现IRepository接口的ApartmentRoomRepository,并在RoomController内部的Add方法中调用ApartmentRoomRepository的insert方法? (据我了解,这种方法似乎不太正确,但我不确定。) 我应该创建 ApartmentRoomViewModel,而不是第一个选项?在这种情况下,如何将房间的 ApartmentID 与房间的 RoomID 插入到 ApartmentRoom 表中?

编辑 1:我使用的是数据库优先方法。

编辑 2:我找到了解决方案并在下面分享为答案。

【问题讨论】:

【参考方案1】:

我从未使用过自动映射器功能,并且有单独的 modelviewmodel 对象,但在这种情况下,我将创建一个新的 ApartmentRoom 对象以及新的 Room 对象,同时保存它们到数据库。创建的ApartmentRoom 模型是存储链接信息的位置。 EF 对于多对多关系不是很明显。

【讨论】:

【参考方案2】:

如果您确定您也处理域类和流利的 API,我认为您使用的不是 EF 核心。您可以从 ApartmentRepository 获取 Apartment,然后将其添加到房间公寓并添加到数据库。

[HttpPost]
public JsonResult Add(RoomViewModel roomModel)

    try
    
        //var apartViewModel = new ApartmentRoomViewModel();
        //apartViewModel.ApartmentID = roomModel.ApartmentNameId;
        var room = AutoMapper.Mapper.Map<Room>(roomModel);
        var apart= apartmentRepository.GetById(roomModel.ApartmentNameId);
        room.Apartments.Add(apart);
        var status = _roomRepository.Insert(room);
        _roomRepository.Save();
        //apartViewModel.RoomID = room.Id;

        return Json(new  status, message = "Ekleme işlemi başarılı." , JsonRequestBehavior.AllowGet);
    
    catch (Exception)
    
        return Json(new  status = false, message = "Hata! Ekleme işlemi gerçekleştirilemedi." , JsonRequestBehavior.AllowGet);
    

【讨论】:

【参考方案3】:

我已经设法找到了解决方案。首先,我在 AutoMapperProfile.cs 文件中添加了一行。

AutoMapperProfile.cs

 public class AutoMapperProfile : Profile

    public AutoMapperProfile()
    
        CreateMap<Room, RoomViewModel>().ReverseMap();
        CreateMap<Apartment, ApartmentViewModel>().ReverseMap();

        // Added this new line
        CreateMap<ApartmentRoom, ApartmentRoomViewModel>().ReverseMap();
    


public class AutoMapperConfig

    public static void Configure()
    
        Mapper.Initialize(x =>
        
            x.AddProfile<AutoMapperProfile>();
        );
    

ApartmentRoom.cs

这个类已经从我的数据库中生成了。

public partial class ApartmentRoom

    public int Id  get; set; 
    public int ApartmentID  get; set; 
    public int RoomID  get; set; 

    public virtual Apartment Apartment  get; set; 
    public virtual Room Room  get; set; 

ApartmentRoomViewModel.cs

我已经创建了这个类。

public class ApartmentRoomViewModel

    public int ApartmentID  get; set; 
    public int RoomID  get; set; 

房间控制器

我稍微改变了RoomController的内部。我创建了一个 _entities 对象,以便能够将数据插入到 ApartmentRoom 表中。

public class RoomController : Controller

    ApartmentManSysEntities _entities = new ApartmentManSysEntities();
    private readonly IRoomRepository _roomRepository;
    private readonly IApartmentRepository _apartmentRepository;
    public RoomController(IRoomRepository roomRepository, IApartmentRepository apartmentRepository)
    
        _roomRepository = roomRepository;
        _apartmentRepository = apartmentRepository;
    

    [HttpPost]
    public JsonResult Add(RoomViewModel roomViewModel)
    
        try
        
            var room = AutoMapper.Mapper.Map<Room>(roomViewModel);
            if (_roomRepository.Insert(room))
            
                _roomRepository.Save();
                var apartRoomViewModel = new ApartmentRoomViewModel
                
                    ApartmentID = roomViewModel.ApartmentNameID,
                    RoomID = room.Id
                ;
                var apartRoom = AutoMapper.Mapper.Map<ApartmentRoom>(apartRoomViewModel);
                _entities.ApartmentRoom.Add(apartRoom);
                _entities.SaveChanges();
            
            else
            
                return Json(new  status = false, message = "Hata! Ekleme işlemi gerçekleştirilemedi." , JsonRequestBehavior.AllowGet);
            
            return Json(new  status = true, message = "Ekleme işlemi başarılı." , JsonRequestBehavior.AllowGet);
        
        catch
        
            return Json(new  status = false, message = "Hata! Ekleme işlemi gerçekleştirilemedi." , JsonRequestBehavior.AllowGet);
        
    


Room 表中添加了一个新房间后,我调用了最后插入的房间的 Id 值来对ApartmentRoom 表进行新的插入。

结果

公寓房桌

房间桌

【讨论】:

我假设 roomViewModel 中的 ID 在插入控制器时为零。也许您也可以尝试Room.ApartmentRoom.ApartmentID = roomViewModel.ApartmentNameID; Room.ApartmentRoom.RoomID = roomViewModel.RoomID;之类的方法,我知道此时 RoomID 仍然为零,但是当您添加两个实体然后保存它们时,数据库会为您创建 id 并自动分配正确的值。如果你尝试,让我知道会发生什么。我很感兴趣。

以上是关于具有存储库模式的实体框架,将数据插入到具有多对多关系的表中的主要内容,如果未能解决你的问题,请参考以下文章

实体框架使用 Codefirst、通用存储库、工作单元模式保存多对多关系

多对多(自相关)特定订单实体框架

插入对象——核心数据

实体框架:多对多插入重复

具有实体框架 4.1 和父/子关系的存储库模式

首先在实体框架代码中与中间对象进行多对多映射