我应该如何设计我的对象模型,以便我的DAL可以填充只读字段?

时间:2022-09-11 18:26:02

In order to separate concerns, on my current project, I've decided to completely separate my DAL and BLL/Business objects in separate assemblies. I would like to keep my business objects as simple structures without any logic to keep things extremely simple. I would like if I could keep my Business Logic separate from my DAL also. So my application will tell my DAL to load my objects, my DAL will run off to the database and get the data, populate the object with the data and then pass it back to my BLL.

为了区分问题,在我当前的项目中,我决定在单独的程序集中完全分离我的DAL和BLL / Business对象。我想将我的业务对象保持为简单的结构,没有任何逻辑来保持简单。我想如果我可以将我的业务逻辑与我的DAL分开。因此,我的应用程序将告诉我的DAL加载我的对象,我的DAL将运行到数据库并获取数据,用数据填充对象,然后将其传递回我的BLL。

Question - how can I have my DAL in a separate assembly and push data into the read only fields?

问题 - 如何将DAL放在单独的程序集中并将数据推送到只读字段?

  • If I set the getter as protected then inherited objects can access it which isn't really what I want as I'd be returning the inherited object types, not the original object types.
  • 如果我将getter设置为protected,那么继承的对象可以访问它,这实际上并不是我想要的,因为我将返回继承的对象类型,而不是原始的对象类型。
  • If I set the getter as internal, then my DAL must reside in the same assembly as my BLL which I don't want.
  • 如果我将getter设置为internal,那么我的DAL必须与我不想要的BLL位于同一个程序集中。
  • If I set the getter as public, then anyone can read/write to it when it should be read only.
  • 如果我将getter设置为public,那么任何人都可以在只读它时读/写它。

Edit: I note that I can have a return type of ObjectBase but actually be returning an object or collection of objects that are derived form ObjectBase so to the outside world (outside my DAL) the properties would be read-only, but my derived types (only accessible inside my DAL) the properties are actually read/write.

编辑:我注意到我可以有一个返回类型的ObjectBase,但实际上是返回一个对象或从ObjectBase派生的对象集合,所以对外界(在我的DAL之外)属性是只读的,但我的派生类型(只能在我的DAL中访问)属性实际上是读/写。

5 个解决方案

#1


7  

You can set the read only property via a constructor.

您可以通过构造函数设置只读属性。

#2


1  

This is a situation without a silver-bullet; the simplest options are limited or don't meet your requirements and the thorough solutions either begin to have smells or begin to veer away from simplicity.

这是没有银弹的情况;最简单的选择是有限的或不符合您的要求,彻底的解决方案要么开始有气味,要么开始偏离简单。

Perhaps the simplest option is one that I haven't seen mentioned here: keeping the fields / properties private and passing them as out / ByRef parameters to the DAL. While it wouldn't work for large numbers of fields it would be simple for a small number.

也许最简单的选项是我在这里没有提到的选项:保持字段/属性私有并将它们作为out / ByRef参数传递给DAL。虽然它不适用于大量的字段,但对于少数字段来说却很简单。

(I haven't tested it, but I think it's worth exploring).

(我没有测试过,但我认为值得探讨)。

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
    }
}

It's also worth noting that trying to keep your domain / business objects to the bare-minimum can involve more than you think. If you intend to databind to them then you'll need to implement IPropertyNotifyChanged, which prevents you from using automatically-implemented properties. You should be able to keep it fairly clean, but you will have to make some sacrifices for basic functionality.

值得注意的是,尝试将域/业务对象保持在最低限度可能比您想象的更多。如果您打算对它们进行数据绑定,那么您将需要实现IPropertyNotifyChanged,这会阻止您使用自动实现的属性。你应该能够保持相当干净,但你必须为基本功能做出一些牺牲。

#3


1  

This keeps your SoC model nicely, it doesn't add in too much complexity, it prevents writing to read-only fields and you could use a very similar model for serialization concerns. Your read-only fields can still be written to by your DAL, as could your serializer if used in a similar fashion - it means that conscious effort must be taken by a developer to write to a read-only field which prevents unintentional misuse.

这样可以很好地保留您的SoC模型,它不会增加太多的复杂性,它会阻止写入只读字段,您可以使用非常相似的模型来处理序列化问题。您的只读字段仍然可以由您的DAL写入,如果以类似的方式使用,您的序列化程序也可以写入 - 这意味着开发人员必须有意识地努力写入只读字段,以防止意外滥用。

Model Project

示范项目

namespace Model
{
    public class DataObject
    {
        public int id { get; protected set; }
        public string name { get; set; }
    }   
}

Data Project

数据项目

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;
        }
    }
}

#4


0  

How about just live with it?

和它一起生活怎么样?

Implement with those guidelines, but don't add such a hard constraint in your model. Lets say you do so, but then come another req where you need to serialize it or do something else, and then you are tied with it.

使用这些指南实现,但不要在模型中添加这样的硬约束。让我们说你这样做,但是然后再来一个你需要序列化或做其他事情的req,然后你就可以了。

As you said in other comment, you want pieces that are interchangeable ... so, basically you don't want something that's tied into specific relations.

正如你在其他评论中所说,你想要的是可互换的部分......所以,基本上你不需要与特定关系相关的东西。


Update 1: Perhaps "just live with it" was too simplistic, but I still have to stress out that you shouldn't go too deep into these things. Using simple guidelines, keeping your code clean and SOLID its the best you can do at the beginning. It won't get in the way of progress while refactoring when everything is more settled isn't hard.

更新1:也许“只是忍受它”太简单了,但我仍然要强调你不应该深入研究这些事情。使用简单的指导原则,保持代码清洁,并在开始时尽力使用SOLID。当一切都更加稳定时,重构不会妨碍进步。

Make no mistake, I am not at all a person that goes writing code without any thinking on it. But, I have gone with such approaches and only in a handful cases they pay off --- without any indication that you wouldn't have a similar result by going simple and evolving it.

毫无疑问,我根本不是一个没有任何思考就编写代码的人。但是,我已经采用了这样的方法,并且只有少数几种情况才能得到回报 - 没有任何迹象表明你不会通过简单和发展来获得类似的结果。

IMHO this one does not fit into important architecture concerns that need to be addressed at the very beginning.

恕我直言,这个问题不适合需要在一开始就解决的重要架构问题。

Pre-emptive follow up: beware if you can't trust your team into following simple guidelines. Also make sure to begin with some structure, pick a couple scenarios that set a structure in with real stuff, the team will know their way much better when there is something simple there.

先发制人的后续行动:请注意,如果您不相信您的团队遵循简单的指导原则。还要确保从一些结构开始,选择一些场景,用真实的东西设置结构,当有简单的东西时,团队会更好地了解他们的方式。

#5


0  

In my opinion, the best way to handle this is to have the business objects and the DAL in the same assembly separated by namespace. This separates the concerns logically and allows you to use internal setters. I can't think of any benefit to separating them into their own assemblies because one is useless without the other.

在我看来,处理此问题的最佳方法是将业务对象和DAL放在由命名空间分隔的同一程序集中。这在逻辑上区分了这些问题,并允许您使用内部设置器。我想不出把它们分成自己的集合会有什么好处,因为没有另一个就没有用。

#1


7  

You can set the read only property via a constructor.

您可以通过构造函数设置只读属性。

#2


1  

This is a situation without a silver-bullet; the simplest options are limited or don't meet your requirements and the thorough solutions either begin to have smells or begin to veer away from simplicity.

这是没有银弹的情况;最简单的选择是有限的或不符合您的要求,彻底的解决方案要么开始有气味,要么开始偏离简单。

Perhaps the simplest option is one that I haven't seen mentioned here: keeping the fields / properties private and passing them as out / ByRef parameters to the DAL. While it wouldn't work for large numbers of fields it would be simple for a small number.

也许最简单的选项是我在这里没有提到的选项:保持字段/属性私有并将它们作为out / ByRef参数传递给DAL。虽然它不适用于大量的字段,但对于少数字段来说却很简单。

(I haven't tested it, but I think it's worth exploring).

(我没有测试过,但我认为值得探讨)。

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
    }
}

It's also worth noting that trying to keep your domain / business objects to the bare-minimum can involve more than you think. If you intend to databind to them then you'll need to implement IPropertyNotifyChanged, which prevents you from using automatically-implemented properties. You should be able to keep it fairly clean, but you will have to make some sacrifices for basic functionality.

值得注意的是,尝试将域/业务对象保持在最低限度可能比您想象的更多。如果您打算对它们进行数据绑定,那么您将需要实现IPropertyNotifyChanged,这会阻止您使用自动实现的属性。你应该能够保持相当干净,但你必须为基本功能做出一些牺牲。

#3


1  

This keeps your SoC model nicely, it doesn't add in too much complexity, it prevents writing to read-only fields and you could use a very similar model for serialization concerns. Your read-only fields can still be written to by your DAL, as could your serializer if used in a similar fashion - it means that conscious effort must be taken by a developer to write to a read-only field which prevents unintentional misuse.

这样可以很好地保留您的SoC模型,它不会增加太多的复杂性,它会阻止写入只读字段,您可以使用非常相似的模型来处理序列化问题。您的只读字段仍然可以由您的DAL写入,如果以类似的方式使用,您的序列化程序也可以写入 - 这意味着开发人员必须有意识地努力写入只读字段,以防止意外滥用。

Model Project

示范项目

namespace Model
{
    public class DataObject
    {
        public int id { get; protected set; }
        public string name { get; set; }
    }   
}

Data Project

数据项目

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;
        }
    }
}

#4


0  

How about just live with it?

和它一起生活怎么样?

Implement with those guidelines, but don't add such a hard constraint in your model. Lets say you do so, but then come another req where you need to serialize it or do something else, and then you are tied with it.

使用这些指南实现,但不要在模型中添加这样的硬约束。让我们说你这样做,但是然后再来一个你需要序列化或做其他事情的req,然后你就可以了。

As you said in other comment, you want pieces that are interchangeable ... so, basically you don't want something that's tied into specific relations.

正如你在其他评论中所说,你想要的是可互换的部分......所以,基本上你不需要与特定关系相关的东西。


Update 1: Perhaps "just live with it" was too simplistic, but I still have to stress out that you shouldn't go too deep into these things. Using simple guidelines, keeping your code clean and SOLID its the best you can do at the beginning. It won't get in the way of progress while refactoring when everything is more settled isn't hard.

更新1:也许“只是忍受它”太简单了,但我仍然要强调你不应该深入研究这些事情。使用简单的指导原则,保持代码清洁,并在开始时尽力使用SOLID。当一切都更加稳定时,重构不会妨碍进步。

Make no mistake, I am not at all a person that goes writing code without any thinking on it. But, I have gone with such approaches and only in a handful cases they pay off --- without any indication that you wouldn't have a similar result by going simple and evolving it.

毫无疑问,我根本不是一个没有任何思考就编写代码的人。但是,我已经采用了这样的方法,并且只有少数几种情况才能得到回报 - 没有任何迹象表明你不会通过简单和发展来获得类似的结果。

IMHO this one does not fit into important architecture concerns that need to be addressed at the very beginning.

恕我直言,这个问题不适合需要在一开始就解决的重要架构问题。

Pre-emptive follow up: beware if you can't trust your team into following simple guidelines. Also make sure to begin with some structure, pick a couple scenarios that set a structure in with real stuff, the team will know their way much better when there is something simple there.

先发制人的后续行动:请注意,如果您不相信您的团队遵循简单的指导原则。还要确保从一些结构开始,选择一些场景,用真实的东西设置结构,当有简单的东西时,团队会更好地了解他们的方式。

#5


0  

In my opinion, the best way to handle this is to have the business objects and the DAL in the same assembly separated by namespace. This separates the concerns logically and allows you to use internal setters. I can't think of any benefit to separating them into their own assemblies because one is useless without the other.

在我看来,处理此问题的最佳方法是将业务对象和DAL放在由命名空间分隔的同一程序集中。这在逻辑上区分了这些问题,并允许您使用内部设置器。我想不出把它们分成自己的集合会有什么好处,因为没有另一个就没有用。