我想将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!!!
}
}
答案 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')