如果未设置属性,请在visual studio中显示警告/错误?

时间:2018-01-11 15:50:47

标签: c# .net

我的模型类包含具有公共get / sets的属性,因为它们被写入/写入db。

我还有一个工厂来创建这些模型,因为启动和底层结构太复杂,无法每次手动创建。

如果未设置某些属性,我的工厂会进行异常处理。

所以这只是一个理论问题。如果某人能够手工创建此模型(不可能,因为它在工厂内部)/与工厂和一个必需属性未设置。 e.g。

Model model = new Model() {A = a, B = b, D = d} //C is missing

是否可能有属性或其他内容,因此编辑器(visual studio)已经显示警告/错误?而不是必须运行代码并点击异常?

2 个答案:

答案 0 :(得分:1)

实际上,这个问题突出了在模型层中暴露POCO数据传输对象时遇到的有趣问题。通常,ORM系统会对您的dtos施加约束,这些约束不一定与您想要的封装兼容。

这意味着您通常需要具有公共setter(例如)的属性,但这会破坏您在创建新模型对象时想要拥有的封装(您希望拥有构造函数)具体需要参数)。

一种可能的解决方案是使用控制反转来将您的域模型层与数据持久层隔离开来。这是一个非常重要的解决方案,但它基本上允许您向模型添加所需的任何代码,同时保持持久性的实现细节远离业务逻辑。它还具有以下优势:您的业务层不需要依赖于您的数据库技术。

注意:根据持久性框架,这不一定只是实现OP的愿望,但这适用于任何持久性框架,并且确实可以轻松地混合和匹配 - 所以你可以从多个数据源和技术中提供业务对象,而无需使用代码,并且无需在业务逻辑中进行特殊考虑。

修改

我使用的模式对于大多数用途来说可能有点过头了 - 虽然它确实受益于完全隔离 - 我能够使用实时网站并使用EF重构后端使用CosmosDB而不使用此方法更改任何模型代码。如果您没有技术隔离的要求,或者能够混合持久性技术,这可能会走得太远:

使用示例:

/// <summary>
/// Example of use.
/// </summary>
public static class UseExample
{
    public static BusinessObjectX DoStuff(BusinessObjectXRepoAbstraction repo)
    {
        var newBox = repo.CreateX("mandatory property");
        //Do stuff...
        return newBox;
    }
}

业务模型层中的定义。

/// <summary>
/// Persistence Technology independent BO.
/// </summary>
public abstract class BusinessObjectX
{
    internal BusinessObjectX()
    {
    }

    public abstract string SomeProperty { get; }
}

/// <summary>
/// Technology independent repository abstraction for BOX - Create could
/// be a static member of <see cref="BusinessObjectX"/>
/// </summary>
public abstract class BusinessObjectXRepoAbstraction
{
    public abstract BusinessObjectX Create(string mandatoryPropertyValue);
}

数据库层中的定义。

    /// <summary>
/// Actual database repository facade for BOX
/// </summary>
internal sealed class BusinessObjectXDatabaseRepo
{
    public BusinessObjectXPoco CreateNew()
    {
        throw new NotImplementedException("Create in database and return POCO");
    }
}

/// <summary>
/// ORM Poco for BOX.
/// </summary>
internal sealed class BusinessObjectXPoco
{
    public Guid Id { get; set; }

    public string SomeProperty { get; set; }
}

业务逻辑层的实现(取决于其他层):

/// <summary>
/// Facade implementation in terms of a particular POCO and database technology.
/// </summary>
internal sealed class BusinessObjectXImpl : BusinessObjectX
{
    private readonly BusinessObjectXPoco poco;

    internal BusinessObjectXImpl(BusinessObjectXPoco poco)
    {
        this.poco = poco;
    }

    public override string SomeProperty => poco.SomeProperty;
}

/// <summary>
/// Allows the lookup of <see cref="BusinessObjectX"/> instances 
/// from POCOs - has the lifecycle of a transaction.
/// </summary>
internal sealed class BusinessObjectXFacadeLookup
{
    private readonly Func<BusinessObjectXPoco, BusinessObjectX> createFunc;
    private readonly Dictionary<Guid, BusinessObjectXImpl> lookup 
        = new Dictionary<Guid, BusinessObjectXImpl>();

    public BusinessObjectXFacadeLookup(Func<BusinessObjectXPoco, BusinessObjectX> createFunc)
    {
        this.createFunc = createFunc;
    }

    public BusinessObjectX GetOrCreate(BusinessObjectXPoco poco)
    {
        BusinessObjectXImpl ret;
        if (!lookup.TryGetValue(poco.Id, out ret))
        {
            ret = new BusinessObjectXImpl(poco);
            lookup.Add(poco.Id, ret);
        }
        return ret;
    }
}

/// <summary>
/// Technology specific repository implementation.
/// </summary>
internal sealed class BusinessObjectXRepoConcrete : BusinessObjectXRepoAbstraction
{
    private readonly BusinessObjectXDatabaseRepo databaseRepo;
    private readonly BusinessObjectXFacadeLookup lookup;

    public BusinessObjectXRepoConcrete(BusinessObjectXDatabaseRepo databaseRepo, 
        BusinessObjectXFacadeLookup lookup)
    {
        this.databaseRepo = databaseRepo;
        this.lookup = lookup;
    }

    public override BusinessObjectX Create(string mandatoryPropertyValue)
    {
        var poco = databaseRepo.CreateNew();
        poco.SomeProperty = mandatoryPropertyValue;
        return lookup.GetOrCreate(poco);
    }
}

答案 1 :(得分:1)

将模型解耦为DTO和OR​​M模型,DTO将处理用于数据库映射的所有验证和ORM模型。

对于DTO验证,我们可以使用不同的方法,如。

  1. 参数化构造函数
  2. 将属性属性设置为必需,并使用类似model.Validate()的通用方法验证模型(但没有Visual Studio提示)

  3. 使用模型必需属性规则(自定义规则)的范围代码分析,它将在运行时之前触发。

  4. 此致

    阿都