按照 Microsoft 数据优先方法教程,MetadataType 无法合并元数据

发布于 2025-01-15 19:50:51 字数 2075 浏览 3 评论 0原文

我试图尽可能简化这个问题,但找不到解决方案或修复。

我遵循了此 Microsoft 教程中的第二种方法(“添加元数据类”)https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/database-first-development/enhancing-data-validation?fbclid=IwAR0_eqraghf-faEqw1d0Fijw9D_su5BGIMMrwQQj4DgYwgiDht5NHLgx3BI

我是首先使用 Razor 使用数据 项目。数据库支架可以毫无问题地创建 dbContext。我想用 Display(Name="") 来注释列。这不能进入脚手架生成的文件,因为它们可能会被覆盖,因此教程说在单独的文件中创建元数据类,然后在另一个单独的文件中创建部分类,以将元数据合并到脚手架生成的类中。我明白这一切,但它不起作用。

为了使其变得非常简单,我创建了一个表 Customer,并在运行脚手架后编辑了脚手架生成的文件,以便所有内容都在一个文件中(因此命名空间没有潜在的问题 - 即使所有内容都在同一个命名空间中......)。

以下是所有代码:

CREATE TABLE [dbo].[Customers] (
      [Id] INT NOT NULL,
      [Name] VARCHAR (30) NOT NULL,
      [Details] VARCHAR (MAX) NOT NULL,
      PRIMARY KEY CLUSTERED ([Id] ASC)
    );

然后,我编辑了脚手架生成的 Customer.cs 类,以包含元数据类和 MetadataType 属性。该文件是:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace MyProject.Models
{
public partial class Customer
{
public int Id { get; set; }
// [Display(Name ="Customer name")]
// if I put the annotation here it works. If I comment this out and put it in the metadata class it doesn't work
public string Name { get; set; } = null!;
public string Details { get; set; } = null!;
}

[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}

public class CustomerMetaData
{
[Display(Name ="Customer name")]
public string Name";
}
}

因此,完成后,我只需在 Pages 文件夹中创建一个文件夹,然后右键单击并添加 >剃刀页面> Razor Pages 与 EF (CRUD) 一起为 dbContext 中的 Customer 类生成默认 CRUD 页面。

就是这样。没什么复杂的。回到 Customer.cs 类文件,如果我将 [Display(Name="Customer Name"] 放在脚手架生成的类中,它会起作用,并且页面显示“客户名称”而不是列名称“名称”。但是,注释掉我将注释放在 Customer 类中,并将 MetaDataType 属性放在第二个部分类 Customer 上,并有一个包含注释的 CustomerMetaData 类,但它不起作用,

因为您看不到它,所以问题变得更加复杂 如果您“观看”,则注释调试期间的数据对象

I have tried to simplify this problem as much as possible and cannot find a solution or fix.

I have followed the second approach ("Add metadata class") in this Microsoft tutorial https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/database-first-development/enhancing-data-validation?fbclid=IwAR0_eqraghf-faEqw1d0Fijw9D_su5BGIMMrwQQj4DgYwgiDht5NHLgx3BI

I am using data first with a Razor project. The database scaffolds without problem to create the dbContext. I want to annotate columns eg with Display(Name=""). This cannot go in the scaffolding generated files because they may get overwritten so the tutorial says to create metadata classes in a separate file and then a partial class in another separate file to merge the metadata into the scaffold generated classes. I understand all of this but it doesn't work.

To make it extremely simply I created a table Customer and after running scaffolding I edited the scaffold generated file so that everything was in the one file (so no potential problems with namespace - even though everything was in the same namespace anyway...).

So here is all of the code:

CREATE TABLE [dbo].[Customers] (
      [Id] INT NOT NULL,
      [Name] VARCHAR (30) NOT NULL,
      [Details] VARCHAR (MAX) NOT NULL,
      PRIMARY KEY CLUSTERED ([Id] ASC)
    );

I then edited the Customer.cs class generated by scaffolding to include the metadata class and MetadataType property. The file is:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace MyProject.Models
{
public partial class Customer
{
public int Id { get; set; }
// [Display(Name ="Customer name")]
// if I put the annotation here it works. If I comment this out and put it in the metadata class it doesn't work
public string Name { get; set; } = null!;
public string Details { get; set; } = null!;
}

[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}

public class CustomerMetaData
{
[Display(Name ="Customer name")]
public string Name";
}
}

So once I've done that I simply created a folder in the Pages folder and right clicked and Add > Razor Page > Razor Pages with EF (CRUD) to generate the default CRUD pages for the Customer class in the dbContext.

So that's it. Nothing complicated. Back in the Customer.cs class file if I put the [Display(Name="Customer Name"] in the Scaffolding generated class it works and the pages display "Customer name" instead of the column name "Name". However, comment out the annotation in the Customer class and put the MetaDataType attribute on a second partial class Customer and have a CustomerMetaData class that includes the annotation and it doesn't work.

I can not get it to work.

The problem is compounded because you cannot see the annotations if you "watch" a data object during debug

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

星軌x 2025-01-22 19:50:51

我遇到了同样的问题。
我使用 .Net 6、ASP.NET、MVC 和 EF Core。

我能够获取显示名称的唯一方法是直接在视图中。我可以忍受这一点,但让我丧命的是我无法以这种方式控制验证内容。

更新:

我有点黑客工作。我使用了模型的子类并在其上添加了注释。该子类仅包含我想要注释的字段的副本。我确实必须使用 [new] 关键字,但这些属性无论如何都会被丢弃。然后我调整视图以使用该子类作为@model。

这就是我改变的一切。我将 EF 上下文保留为指向原始类。所有控制器都一样。依赖注入侏儒会查看控制器所期望的内容(原始类)并以这种方式进行管道传输。

不过,我对此并不是百分百满意。尽管代码影响与元数据类和属性组合相同,但它的作用或原因并不明显可理解。并且存在对依赖注入正常工作的隐藏依赖。

更新 #2:

我更改了所有这些,以使用应用于接口的数据注释。我能够将该接口应用于模型部分类的“用户安全”侧,实际上只是一个存根,并更改了视图上的 @model 标签以使用该接口。我认为它更干净,并且类之间没有一些隐藏的上下文切换。

I'm experiencing the same issue.
I'm in .Net 6, ASP.NET, MVC, with EF Core.

The only way I'm able to get my display name is directly in the view. I can live with that but what's killing me is I can't control the validation stuff that way.

Update:

I somewhat have a hack working. I used a subclass of the model and put the annotations on that. The subclass includes only a copy of the fields I wanted to annotate. I did have to use the [new] keyword but those properties are throw-away anyway. I then adjust the view to use that subclass as the @model.

That's all I changed. I leave the EF context pointing to the original class. The same with all the controllers. The dependency injection gnomes look at what the controller is expecting (the original class) and pipe it in that way.

I'm not 100% happy with this, though. Even though the code impact is the same thing as the metadata class and attribute combo, it's not visibly understandable as to what or why it's doing it. And there is the hidden dependency on dependency injection working correctly.

Update #2:

I changed all of this around to use the data annotation applied to an interface instead. I was able to apply the interface to "user safe" side of the model partial classes, just a stub really, and changed the @model tag on the views to use the interface. I think it's much cleaner and there isn't some hidden context switching between classes.

花开浅夏 2025-01-22 19:50:51

找到了一个使用接口工作的解决方案,约瑟夫也善意地确认他有一个使用接口工作的解决方案(约瑟夫也是你的解决方案)。为了将来阅读本文的任何人的利益,这就是我设法做的事情(让我知道是否有更好的解决方案)。

脚手架生成的 Customer 类(不应对其进行编辑,以避免编辑被后续脚手架覆盖)

namespace project.Models
{
    public partial class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; } = null!;
        public string Info { get; set; } = null!;
    }
}

在 Models 文件夹中创建一个名为 CustomerExtension.cs 的单独类文件,

namespace project.Models
{
    public partial class Customer : ICustomer
    { }

    public interface ICustomer
    {
        int Id { get; }
        [Display(Name = "Customer name")]
        string Name { get; set; }
        [Display(Name = "Customer info")]
        string Info { get; set; }

    }
}

然后在 Razor 或 MVC 文件中使用 ICustomer 而不是 Customer。可以自动生成 CRUD 页面/视图的脚手架工具不喜欢使用界面作为模型(至少它不适合我),所以我使用 Customer 生成它们,然后编辑页面/视图模型以使用 ICustomer那个客户。因此,在视图等页面中,将模型属性更改为:

public ICustomer Customer { get; set; }

对于仅显示单个记录/行的简单页面/视图(例如“详细信息”页面和 Customer = wait _context.Customers.FirstOrDefaultAsync( m => m.Id == id); 有效。但是,对于显示记录/行列表的索引页面,查询生成了错误。我可能粗略的解决方案是在查询中的 select 语句中转换数据值:

Customer = await _context.Customers.Select(e => (ICustomer)e).ToListAsync();

然后它就可以工作并使用接口中定义的注释。

Found a solution that works using interfaces and Joseph has kindly also confirmed that he's got a solution using interfaces that works (Joseph is your solution the same). For the benefit of anybody reading this in the future here's what I managed to do (let me know if there is a better solution).

scaffolding generated Customer class (which shouldn't be edited to avoid edits being overwritten by subsequent scaffolding) is

namespace project.Models
{
    public partial class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; } = null!;
        public string Info { get; set; } = null!;
    }
}

Created a separate class file in the Models folder called CustomerExtension.cs

namespace project.Models
{
    public partial class Customer : ICustomer
    { }

    public interface ICustomer
    {
        int Id { get; }
        [Display(Name = "Customer name")]
        string Name { get; set; }
        [Display(Name = "Customer info")]
        string Info { get; set; }

    }
}

Then in the Razor or MVC files use ICustomer rather than Customer. The scaffolding tool that can auto generate CRUD pages/views doesn't like using the interface as the model (well at least it didn't for me) so I generated them using Customer and then edited the page/view models to use ICustomer rather that Customer. So in pages such as view changed the model property to:

public ICustomer Customer { get; set; }

This was all I needed to do for simple pages/views that simply display a single record/row such as the Details page and Customer = await _context.Customers.FirstOrDefaultAsync(m => m.Id == id);works. However, for the Index page that displays a list of records/rows the query generated an error. My perhaps crude solution was to cast the data value in a select statement in the query:

Customer = await _context.Customers.Select(e => (ICustomer)e).ToListAsync();

That then works and uses the annotations defined in the interface.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文