如何克服数据库插入方法设计挑战中的返回ID

时间:2015-11-22 17:36:52

标签: c# oop design-patterns solid-principles

这可能是一个很长的帖子,但请耐心等待。基本思路是:

public int InsertPersonAndGetPersonId(Person person){
    _dbContext.Insert(person);
    return person.PersonId;
}

上述方法很简单,但违反了清晰的编程原则。

  1. 方法中的命令/查询分离。
  2. 它不止一份工作。
  3. 当我评估不同的方法时,我通常会列出利弊,并选择利弊最少且权衡最少的方法。因此,老实说,上述方法看起来比下面列出的替代方案更好。但我仍然希望得到SO社区的意见,也许我会学习一种最适合这一挑战的新模式。

    备选方案#1

    另一种方法是使用两种方法。当一个是插入新记录时,另一个从数据库中获取最后添加的personId。但这是不可靠的,除非您阻止数据库在插入记录和从数据库中获取其ID之间接受新人插入。

    您甚至可以在从数据库获取记录时通过Person(例如Name)的属性进行过滤,但除了我上面所说的,还可以有多个人谁具有相同的名称但PersonId s。

    它还在进行一次数据库访问。我是一个务实的人,不想在没有实际测量的情况下推测性能。但是,如果我可以通过简单的改变来防止某些事情,甚至会略微提高性能,那么我觉得不这样做是愚蠢的。当然,在执行此操作时,我也会考虑清洁代码实践。

    备选方案#2

    另一种方法可以是更改InsertPersonAndGetPersonId,并具有以下内容:

    public class PersonRepository
    {
        private int _personId;
    
        public void InsertPerson(Person person){
            _dbContext.Insert(person);
            _personId = person.PersonId;
        }
    
        public int GetLastPersonId
            return _personId;
        }
    } 
    

    即使我不喜欢此方法的名称GetLastPersonId(),但这可能会带来与预期不同的personId,但让我们假设它返回id } person对象。它是坏的原因,除了我已经说过,它正在修改对象的状态,因此有副作用。

    备选方案#3

    我们可以简单地使用以下方法:

    public void InsertPerson(Person person){
        _dbContext.Insert(person);
        _personId = person.PersonId;
    }
    

    由于person是引用类型,我们可以访问person.PersonId,如下所示:

    var personRepository = new PersonRepository();
    var person = new Person() {Name="Hello"};
    personRepository.InsertPerson(person);
    Console.WriteLine(person.PersonId);
    

    我喜欢它吗?没有!这是太隐蔽和不可预测的,你不会真正了解它,除非你检查实现细节,然后我们打破抽象的美丽。

    备选方案#4

    我们可以使用out,如下所示:

    public void InsertPerson(Person person, out int personId){
        _dbContext.Insert(person);
        personId = person.PersonId;
    }
    

    但这看起来比第一个InsertPersonAndGetPersonId更愚蠢和笨拙。如果我将不得不返回一些内容,那么我将使用return返回它,并使开发人员更明确地签名。事实上,当我们需要返回多个值时,outref更有意义。例如TryParse(),返回boolean,但您也可以使用outref获取解析后的值。

    更新

    由于一些评论,我决定更多地澄清我的问题。我要问的是如何在不违反清洁代码原则的情况下获得PersonId。我正在使用EF,因此从数据库获取id不是问题,事实上你可以在我的第一个例子中看到它。对不起,感到困惑。

2 个答案:

答案 0 :(得分:2)

你考虑过举办活动吗? PersonCreatedEvent另请参阅:http://blog.ploeh.dk/2014/08/11/cqs-versus-server-generated-ids/

答案 1 :(得分:0)

显然你的设计有问题。您返回此PersonId的事实意味着您需要它来识别域逻辑中的人(如果您愿意,则为业务逻辑)。

问题是:什么数据库ID与人物身份有关?它在您的域名中是否有任何意义? 如果没有,则使用其他方法来识别域逻辑中的Person。这将至少为您带来以下好处:

  1. 您将能够创建具有Factory的人员(如果它是一个实体并且可能是聚合根),使他对您的域逻辑身份有意义。

  2. 您将能够使用存储库保存新创建的人员,并且不必在您的域逻辑中处理它的数据库ID。

  3. 然后你就能写出这样的东西:

    var newPerson = PersonFactory.Create();
    //do some work with person in domain logic  
    PersonRepository.Persist(newPerson);