3

我有一个方法可以在数据库中创建一些条目并返回它的Id。我想以某种方式将这两者分开,因为它违反了命令-查询分离。
例如方法(简化):

int CreatePost(database::Post newPost)
{
    using(var db = new database::MainModelContainer())
    {
        db.Posts.Add(newPost);
        db.SaveChanges();
        return newPost.Id;
    }
}

我知道有使用refout的解决方法,但我认为这些解决方案unclean。我想要具有以下签名的命令。

void CreatePost(database::Post newPost)

有没有办法我可以做到这一点?注意:我需要在创建后立即
知道新创建的条目的Id是什么。

4

3 回答 3

2

保存实体后,实体框架使用适当的值填充 Id 属性。因此,如果您有一个实体:

public class Post
{
    public int Id { get; set; } // primary key
    ...
}

以及保存它的方法:

public void SavePost(Post post)
{
    using (var db = new YourDatabase())
    {
        db.Posts.Add(post);
        db.SaveChanges();
    }
}

您可以从客户端代码执行此操作以获取 id:

var myPost = new Post();
Console.Writeline(myPost.Id); // displays 0
SavePost(myPost);
Console.Writeline(myPost.Id); // displays the new id
于 2014-09-23T14:31:14.667 回答
1

这可以通过备忘录模式来解决,只是您似乎不需要备忘录附带的所有撤消能力。Post插入对象后捕获对象状态的简单方法将起作用:

public class PostCreator 
{
    public PostCreator()
    {
        CreatedId = null;
    }

    public void CreatePost(database::Post newPost)
    {
        if (CreatedPostId != null)
            throw new InvalidOperationException("Post Already Created!");

        using(var db = new database::MainModelContainer())
        {
            db.Posts.Add(newPost);
            db.SaveChanges();
            CreatedPostId = newPost.Id;
        }
    }

    public int? CreatedPostId { get; private set; }
}

每次创建新帖子时,您都将构建其中一个创建者来为您完成。您可以随时查询该CreatedPostId属性,而不必担心影响状态。

于 2014-01-31T04:06:51.470 回答
1

Mark Seemann 在http://blog.ploeh.dk/2014/08/11/cqs-versus-server-generated-ids/上有一个很好的答案。

简短的版本不依赖于数据库生成的 ID,而是创建自己的密钥并使用它(他建议使用 GUID)。

数据库可能仍会生成身份密钥供其内部使用;这些可以在遵守 CQS 的情况下进行查询。这实际上实现了几个好的实践:它将应用程序与数据库实现分开(并非所有数据库都具有自动身份生成或实现相同),并且它本质上不鼓励将内部顺序 ID 暴露给用户,这可能是一个安全漏洞(OWASP前 10 名 #4 不安全的直接对象引用)。

于 2015-11-05T21:09:41.943 回答