如何在解耦数据层中设置主键
How to set primary key in decoupled datalayer
我想将 BL 与 DAL 分离。特别是我想保护主键(我不希望我的业务用户修改 Item.Id)。
在我的 DataLayer 中(假设它是一个简单的 sql table,带有自动生成的主键)我尝试插入项目并更新 item.Id。
我当然不能,因为它受到保护 属性。
有没有不用反射的方法?
(我的意思是也许我的架构是错误的...)
业务层:
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(使用 EntityFramework 和 sql 服务器):
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!!!
}
}
您应该在数据库中完成此操作。如何执行此操作取决于您使用的数据库。
如果您需要通过代码专门设置一些其他 ID,我建议您专门为此添加另一个 属性,并让您的数据库仍然生成主键。
例如,您可以使用 Dapper 调用一个存储过程来执行您想要的插入(以及任何密钥生成)。
如我的评论所述
如果您正在使用 SQL 服务器,那么您可以在 Db 本身上设置它,无需再做任何事情
create table test
(
Id int Identity(1,1) primary key ,
Name varchar(100)
)
您也可以将现有的 int 列也更改为标识。使用 alter table sql 命令
只要您使用 auto-generated 顺序整数作为主键,您就会遇到一些保护数据的问题。您必须将密钥从服务器传递到客户端,因此当用户更新数据时,您可以找到关联的记录。恶意用户只要改变主键的值,就可以使用不同的工具改变PK,访问不同的记录,因为很容易猜出其他记录的PK值。这些你当然知道。
此问题的行业标准解决方案是使用不易猜到的密钥(不是顺序整数值)。如果您使用 SQL 服务器作为数据库,您可以向 table 添加一个新列,类型定义为 GUID,并将其用作 PK。 GUID 值将由服务器自动分配,它不是顺序的,很难猜测其他值。我对其他数据库引擎不熟悉,但总之,解决方案是使用GUID。
以下是如何声明列并在 table 中添加行(从这篇 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')
为了防止您的逻辑被意外修改Id
,您可以使用"property injection pattern":
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; }
}
我想将 BL 与 DAL 分离。特别是我想保护主键(我不希望我的业务用户修改 Item.Id)。
在我的 DataLayer 中(假设它是一个简单的 sql table,带有自动生成的主键)我尝试插入项目并更新 item.Id。 我当然不能,因为它受到保护 属性。
有没有不用反射的方法? (我的意思是也许我的架构是错误的...)
业务层:
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(使用 EntityFramework 和 sql 服务器):
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!!!
}
}
您应该在数据库中完成此操作。如何执行此操作取决于您使用的数据库。
如果您需要通过代码专门设置一些其他 ID,我建议您专门为此添加另一个 属性,并让您的数据库仍然生成主键。
例如,您可以使用 Dapper 调用一个存储过程来执行您想要的插入(以及任何密钥生成)。
如我的评论所述
如果您正在使用 SQL 服务器,那么您可以在 Db 本身上设置它,无需再做任何事情
create table test
(
Id int Identity(1,1) primary key ,
Name varchar(100)
)
您也可以将现有的 int 列也更改为标识。使用 alter table sql 命令
只要您使用 auto-generated 顺序整数作为主键,您就会遇到一些保护数据的问题。您必须将密钥从服务器传递到客户端,因此当用户更新数据时,您可以找到关联的记录。恶意用户只要改变主键的值,就可以使用不同的工具改变PK,访问不同的记录,因为很容易猜出其他记录的PK值。这些你当然知道。
此问题的行业标准解决方案是使用不易猜到的密钥(不是顺序整数值)。如果您使用 SQL 服务器作为数据库,您可以向 table 添加一个新列,类型定义为 GUID,并将其用作 PK。 GUID 值将由服务器自动分配,它不是顺序的,很难猜测其他值。我对其他数据库引擎不熟悉,但总之,解决方案是使用GUID。
以下是如何声明列并在 table 中添加行(从这篇 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')
为了防止您的逻辑被意外修改Id
,您可以使用"property injection pattern":
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; }
}