如何在解耦数据层中设置主键

时间:2017-01-21 17:52:31

标签: c# n-tier-architecture

我想将BL与DAL分离。特别是我希望保护主键(我不希望我的业务用户修改Item.Id)。

在我的DataLayer中(让我们假设它是一个带有自动生成主键的简单sql表)我尝试插入项目并更新item.Id. 当然我不能因为它是受保护的财产。

有没有办法在不使用反射的情况下执行此操作? (我的意思是我的架构可能错了......)

BusinessLayer:

public class Item
{
    public int Id { get; protected set; }

    public string Name { get; set; }
}

public interface IRepository<Item>
{
    void Insert(Item item);

    //and other CRUD operations
}

DataLayer(使用带有sqlserver的EntityFramework):

public class EfRepository : IRepository<Item>
{
    EfContext ctx;     
    public void Insert(Item item)
    {      
        //EfContext uses its ItemEntity, so I have to map Item to EntityItem
        var mapped = AutoMapper.Map<Item, EntityItem>(item);
        ctx.Items.Add(mapped); 
        //after this operation EF will set primary key to mapped object
        //and now I need to set this to primary key to my business
        //domain object.
        item.Id = ?? // can't set protected property!!!
    }
}

4 个答案:

答案 0 :(得分:1)

您应该在数据库中完成此操作。如何执行此操作取决于您使用的数据库。

如果您需要通过代码专门设置其他ID,我建议您专门为其添加另一个属性,并让您的数据库仍然生成主键。

例如,您可以使用Dapper调用将执行插入(以及任何密钥生成)的存储过程。

答案 1 :(得分:1)

正如我的评论所述

如果您使用的是SQL服务器,那么您可以在Db上设置它本身无需再做任何其他事情

 create table test 
(
 Id int Identity(1,1) primary key ,
   Name varchar(100)
  )

您也可以将现有的int列更改为identity。使用alter table sql命令

答案 2 :(得分:1)

为保护您的逻辑免遭意外修改Id,您可以使用“属性注入模式”:

public class Item
{
    public Item() 
    { 
        _id = -1; 
    }

    public int Id 
    { 
        get 
        { 
            return _id; 
        }

        set
        {
             if (_id != -1)
             {
                 throw new OperationException("Item.Id has already been set");
             }

             _id = value;
        }
    }

    public string Name { get; set; }
}

答案 3 :(得分:0)

只要您使用自动生成的主键顺序整数,您就会遇到保护数据的几个问题。您必须将密钥从服务器传递到客户端,因此当用户更新数据时,您可以找到关联的记录。恶意用户可以使用不同的工具更改PK,只需更改主键的值即可访问不同的记录,因为很容易猜测其他记录的PK值。当然你知道这一切。

此问题的行业标准解决方案是使用不易猜测的密钥(不是连续的整数值)。如果您使用SQL Server作为数据库,则可以向表中添加一个新列,其类型定义为GUID并将其用作PK。 GUID值将由服务器自动分配,它不是顺序的,并且很难猜测其他值。我不熟悉其他数据库引擎,但简而言之,解决方案是使用GUID。

以下是如何声明列并在表中添加行(从此MSDN文章复制而来:https://technet.microsoft.com/en-us/library/ms190215(v=sql.105).aspx

CREATE TABLE MyUniqueTable
   (UniqueColumn   UNIQUEIDENTIFIER      DEFAULT NEWID(),
   Characters      VARCHAR(10) )
GO
INSERT INTO MyUniqueTable(Characters) VALUES ('abc')
INSERT INTO MyUniqueTable VALUES (NEWID(), 'def')