C# 我应该如何设计我的对象模型,以便我的DAL可以填充只读字段?
为了分离关注点,在我当前的项目中,我决定在单独的程序集中完全分离DAL和BLL/业务对象。我希望将我的业务对象保持为简单的结构,而不使用任何逻辑来保持事情极其简单。我希望我能将我的业务逻辑与DAL分开。因此,我的应用程序将告诉我的DAL加载我的对象,我的DAL将运行到数据库并获取数据,用数据填充对象,然后将其传递回我的BLL 问题-如何将DAL放在单独的程序集中,并将数据推送到只读字段中C# 我应该如何设计我的对象模型,以便我的DAL可以填充只读字段?,c#,.net,asp.net,C#,.net,Asp.net,为了分离关注点,在我当前的项目中,我决定在单独的程序集中完全分离DAL和BLL/业务对象。我希望将我的业务对象保持为简单的结构,而不使用任何逻辑来保持事情极其简单。我希望我能将我的业务逻辑与DAL分开。因此,我的应用程序将告诉我的DAL加载我的对象,我的DAL将运行到数据库并获取数据,用数据填充对象,然后将其传递回我的BLL 问题-如何将DAL放在单独的程序集中,并将数据推送到只读字段中 如果我将getter设置为protected,那么继承的对象可以访问它,这并不是我真正想要的,因为我将返回
- 如果我将getter设置为protected,那么继承的对象可以访问它,这并不是我真正想要的,因为我将返回继承的对象类型,而不是原始的对象类型
- 如果我将getter设置为internal,那么我的DAL必须与我不想要的BLL驻留在同一个程序集中
- 如果我将getter设置为public,那么任何人都可以在它应该是只读的时候读/写它
编辑:我注意到,我可以使用ObjectBase的返回类型,但实际上是返回从ObjectBase派生的对象或对象集合,因此到外部世界(在我的DAL外部),属性将是只读的,但我的派生类型(仅在我的DAL内部可访问)属性实际上是读/写的。您可以通过构造函数设置只读属性。如何使用它 使用这些指导原则来实现,但不要在模型中添加这样一个硬约束。假设您这样做了,但随后出现另一个req,您需要序列化它或执行其他操作,然后您就与它绑定在一起了 正如你在其他评论中所说,你想要的是可以互换的部件。。。所以,基本上你不想要与特定关系有关的东西
更新1:也许“接受它”太简单了,但我还是要强调的是,你不应该深入这些事情。使用简单的指导原则,保持代码干净和坚实,这是您在开始时所能做的最好的事情。当一切都变得更加稳定时,它不会妨碍重构的进程,这并不难 别搞错了,我根本不是一个不假思索地写代码的人。但是,我已经采用了这种方法,只有在少数情况下,它们才有回报——没有任何迹象表明,通过简单化和进化,你不会得到类似的结果 IMHO这一点不适合在一开始就需要解决的重要架构问题
先发制人的跟进:如果您不能信任您的团队遵循简单的指导原则,请小心。也要确保从一些结构开始,选择几个场景,用真实的东西设置一个结构,当那里有简单的东西时,团队会更好地了解他们的方式。这是一个没有银弹的情况;最简单的选择是有限的或不符合您的要求,彻底的解决方案要么开始有味道,要么开始偏离简单性 也许最简单的选择是我在这里没有提到的:将字段/属性保持私有,并将它们作为
out
/ByRef
参数传递给DAL。虽然它对大量字段不起作用,但对少量字段则很简单
(我还没有测试过,但我认为值得探索)
公共类MyObject()
{
私人内部Id;
公共int-Id{get{return{u-Id;}}//只读
公共字符串名称{get;set;}
//该方法本质上是一个更具描述性的构造函数,使用存储库模式分离域和持久性
公共静态MyObject GetObjectFromRepo(IRepository repo)
{
MyObject结果=新的MyObject();
返回repo.BuildObject(结果,out\u Id);
}
}
公共类MyRepo:IRepository
{
公共MyObject BuildObject(MyObject objectShell,out int id)
{
字符串objectName;
int objectId;
//检索名称和值属性
objectName=“数据库中的名称”;
objectId=42;
//
objectShell.Name=objectName;
Console.WriteLine(objectShell.Id);//这样可以很好地保持SoC模型,不会增加太多的复杂性,它可以防止写入只读字段,并且您可以使用非常类似的模型进行序列化。您的只读字段仍然可以由DAL写入,如果以类似的方式使用,您的序列化程序也可以这样做-这意味着必须采取有意识的措施由开发人员写入只读字段,以防止意外误用
模型项目
数据项目
命名空间数据
{
类DALDataObject:DataObject
{
公共数据对象(int-id,字符串名)
{
this.id=id;
this.name=名称;
}
}
公共类连接器
{
公共静态数据对象LoadDataObject(int objectId)
{
返回新的DALDataObject(objectId,string.Format(“伪对象{0}”,objectId));
}
公共静态IEnumerable LoadDataObjects(int startRange、int endRange)
{
var list=新列表();
对于(变量i=startRange;i
在我看来,处理这一问题的最佳方法是让业务对象和DAL在同一个程序集中按名称空间分隔。这在逻辑上分隔了关注点,并允许您使用内部setter。我想不出将它们分隔为自己的程序集有什么好处,因为一个没有另一个就没有用处了。有ason,如果你想做出正确的决定
public class MyObject()
{
private int _Id;
public int Id { get { return _Id; } } // Read-only
public string Name { get; set; }
// This method is essentially a more descriptive constructor, using the repository pattern for seperation of Domain and Persistance
public static MyObject GetObjectFromRepo(IRepository repo)
{
MyObject result = new MyObject();
return repo.BuildObject(result, out _Id);
}
}
public class MyRepo : IRepository
{
public MyObject BuildObject(MyObject objectShell, out int id)
{
string objectName;
int objectId;
// Retrieve the Name and Value properties
objectName = "Name from Database";
objectId = 42;
//
objectShell.Name = objectName;
Console.WriteLine(objectShell.Id); // <-- 0, as it hasn't been set yet
id = objectId; // Setting this out parameter indirectly updates the value in the resulting object
Console.WriteLine(objectShell.Id); // <-- Should now be 42
}
}
namespace Model
{
public class DataObject
{
public int id { get; protected set; }
public string name { get; set; }
}
}
namespace Data
{
class DALDataObject : DataObject
{
public DALDataObject(int id, string name)
{
this.id = id;
this.name = name;
}
}
public class Connector
{
public static DataObject LoadDataObject(int objectId)
{
return new DALDataObject(objectId, string.Format("Dummy object {0}", objectId));
}
public static IEnumerable<DataObject> LoadDataObjects(int startRange, int endRange)
{
var list = new List<DataObject>();
for (var i = startRange; i < endRange; i++)
list.Add(new DALDataObject(i, string.Format("Dummy object {0}", i)));
return list;
}
}
}