【问题标题】:Set property to another property's value将属性设置为另一个属性的值
【发布时间】:2017-08-20 14:35:57
【问题描述】:

我对此很陌生,我的问题非常特殊。我用谷歌搜索了很多,但找不到任何关于此的内容。我在数据库中有两个属性,StartDate 和 StartMonth。 StartDate 是 DateTime 类型,而 StartMonth 是字符串类型。 (我知道将这两个都保存到数据库中很愚蠢,但这不是我可以更改的,因为我没有权限这样做。)我的问题是如何在数据库模型中将 StartMonth 设置为等于StartDate 中的月份(因为它是相同的)?相反,这样做的正确方法是什么?非常感谢任何帮助!

要清楚我目前有:

[Table("EMPLOYMENT")]
public class Employment : EntityBase
{   
    [Column("STARTDATE")]
    public DateTime? StartDate { get; set; }

    [Column("STARTMONTH")]
    public string StartMonth { get; set; }
}

编辑: 我尝试了以下方法(我意识到这不是任何建议,但它是由同事建议的):

[Table("EMPLOYMENT")]
public class Employment : EntityBase
{   
    [Column("STARTDATE")]
    internal DateTime? StartDateInternal { get; set; }

    [Column("STARTMONTH")]
    private string StartMonth { get; set; }

    [NotMapped]
    public DateTime? StartDate
    {
        get
        {
            return StartDateInternal;
        }
        set
        {
            StartDateInternal = value;
            StartMonth = value?.ToString("MMMM");
        }
}

具体来说,StartMonth 现在是私有的,StartDate 现在是一个 NotMapped 属性,它设置 StartDateInternal 和 StartMonth 并返回 StartDateInternal 值,而之前代码中的原始 StartDate 现在名为 StartDateInternal。虽然我可以看到该值一直正确传递给模型,但它不会设置该值。它总是在数据库中将其设置为 NULL。我不知道为什么,想知道是否有人能明白为什么。

【问题讨论】:

  • 您可以直接从您的表中更改表架构,设置 STARTMONTH = Datepart(mm,STARTDATE)
  • 如果可以的话,但我没有权限弄乱表架构,我们的表是从 Oracle 数据库(Oracle 到 SQL)中提取的,所以弄乱架构可能会搞砸这个过程也是如此。

标签: c# asp.net asp.net-mvc


【解决方案1】:

您不应该映射 StartMonth 属性,因此它不会保存在数据库中,但模型仍然具有该属性。您可以执行以下操作:

    [NotMapped]
    public string StartMonth
    {
        get
        {
            return StartDate?.Month.ToString();
        }
    }

NotMapped 属性告诉 EF 不映射此属性,但您可以在代码中使用此属性。此外,您不需要设置属性,因为 StartMonth 只会返回 StartDate 月份。这样可以确保 StartMonth 和 StartDate.Month 没有不同的值。

【讨论】:

  • 如果在整个代码中都使用了 setter,这会破坏所有内容并且您可以 100% 确定 StartMonth 和 StartDate 始终正确设置在一起...标记属性为deprecated,它将告诉其他开发人员将来不要使用它,并添加一个记录警告但不执行任何其他操作的设置器...即使您确定,运行完整的测试套件并检查您的所有警告接收。
  • Erik 表示他不能乱用数据库设计,这让我相信这个数据库很可能是按照旧的大型机设计建模的,比如 VSAM、DL/1 或 IDMS。当与具有旧根的设计一起存储时,经常会看到日期被分解成各个部分。无论哪种方式,如果他的应用程序要更新此数据库,他必须选择使用该数据库的其他应用程序可以接受的技术。
  • 埃里克是谁?无论哪种方式,它都无法更改。
【解决方案2】:

你能改变数据库设计吗?

如果是这样,请使用数据库中的触发器或其他工具将 STARMONTH 列呈现为伪列,返回 STARTDATE 列的“月”值。

如果没有,则可以在处理新的 StartDate 时设置 StartMonth:

    [Table("EMPLOYMENT")]
    public class Employment
    {
        private DateTime _StartDate;

        [Column("STARTDATE")]
        public DateTime StartDate
        {
            get
            {
                return _StartDate;
            }
            set
            {
                _StartDate = value;
                StartMonth = value.ToString("MMMM") ?? null;

            }
        }

        [Column("STARTMONTH")]
        public string StartMonth { get; set; }

    }

数据库伪列将保证所有数据库客户端的结果一致。上面的代码适用于任何使用此代码的东西。

【讨论】:

  • 很遗憾,我无法更改数据库设计。不过,我确实尝试了类似于您建议的方法。我已经编辑了我的问题以反映它。
【解决方案3】:

您可以使用支持字段,并从 StartDate 获取月份仅当 StartMonth 值不是放。

private string _startMonth;

[Column("STARTMONTH")]
public string StartMonth
{
    get
    {
        if (string.IsNullOrWhiteSpace(_startMonth) && StartDate.HasValue)
            return StartDate.Value.ToString("MMMM");
        return _startMonth;
    }
    set { _startMonth = value; }
}

【讨论】:

  • 这里有可能有人在脚下开枪new Employment() { StartDate = new DateTime(12,1,1), StartMonth = "January" }
  • 是的,它可能会发生。问题是如果 StartMonth 没有设置器,实体框架将抛出​​异常。如果您根本不信任设置值,则可以删除 string.IsNullOrWhiteSpace(_startMonth)
  • 看起来 StartMonth 是从数据库中进来的,因此需要一个 setter。
【解决方案4】:

将您的设置器标记为private,然后创建一个设置这两个属性的SetStartDate 方法。

[Table("EMPLOYMENT")]
public class Employment : EntityBase
{   
    [Column("STARTDATE")]
    public DateTime? StartDate { get; private set; }

    [Column("STARTMONTH")]
    public string StartMonth { get; private set; }

    public string SetStartDate(DateTime? startDate)
    {
        this.StartDate = startDate;
        this.StartMonth = startDate.HasValue ? startDate.Value.ToString("MMMM") : null;
    }
}

另一种建模方法是将StartMonth 的setter 标记为private,并让StartDate 的setter 设置两个属性:

[Table("EMPLOYMENT")]
public class Employment : EntityBase
{   
    DateTime? startDate;

    [Column("STARTDATE")]
    public DateTime? StartDate
    {
        get { return this.startDate; }
        set
        {
            this.startDate = value;
            this.StartMonth = value.HasValue ? value.Value.ToString("MMMM") : null;
        }
    }

    [Column("STARTMONTH")]
    public string StartMonth { get; private set; }
}

【讨论】:

  • 设置私有有什么作用?或者,更确切地说,为什么要这样做?
  • 主要是为了防止用户在脚上开枪。他们可以指定一个StartDate,它将自动计算StartMonth。他们无法为这些字段指定冲突的值。
  • 为了澄清,当我说“用户”时,我的意思是“开发者”......如果不跳过箍,他们(甚至你)将无法弄乱这些值。通过为 StartDate 指定单个值,将自动设置这两列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-07
相关资源
最近更新 更多