{"action":"created","issue":{"url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/issues/7132","repository_url":"https://api.github.com/repos/aspnet/EntityFrameworkCore","labels_url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/issues/7132/labels{/name}","comments_url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/issues/7132/comments","events_url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/issues/7132/events","html_url":"https://github.com/aspnet/EntityFrameworkCore/issues/7132","id":191819897,"number":7132,"title":"Type Metadata - Add DataDomain Attribute and Domain Concepts","user":{"login":"RandyBuchholz","id":13967891,"avatar_url":"https://avatars0.githubusercontent.com/u/13967891?v=4","gravatar_id":"","url":"https://api.github.com/users/RandyBuchholz","html_url":"https://github.com/RandyBuchholz","followers_url":"https://api.github.com/users/RandyBuchholz/followers","following_url":"https://api.github.com/users/RandyBuchholz/following{/other_user}","gists_url":"https://api.github.com/users/RandyBuchholz/gists{/gist_id}","starred_url":"https://api.github.com/users/RandyBuchholz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RandyBuchholz/subscriptions","organizations_url":"https://api.github.com/users/RandyBuchholz/orgs","repos_url":"https://api.github.com/users/RandyBuchholz/repos","events_url":"https://api.github.com/users/RandyBuchholz/events{/privacy}","received_events_url":"https://api.github.com/users/RandyBuchholz/received_events","type":"User","site_admin":false},"labels":[{"id":679361878,"url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/labels/propose-close","name":"propose-close","color":"fef2c0","default":false},{"id":333904587,"url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/labels/type-investigation","name":"type-investigation","color":"0052cc","default":false}],"state":"closed","locked":false,"assignee":{"login":"divega","id":1253414,"avatar_url":"https://avatars0.githubusercontent.com/u/1253414?v=4","gravatar_id":"","url":"https://api.github.com/users/divega","html_url":"https://github.com/divega","followers_url":"https://api.github.com/users/divega/followers","following_url":"https://api.github.com/users/divega/following{/other_user}","gists_url":"https://api.github.com/users/divega/gists{/gist_id}","starred_url":"https://api.github.com/users/divega/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/divega/subscriptions","organizations_url":"https://api.github.com/users/divega/orgs","repos_url":"https://api.github.com/users/divega/repos","events_url":"https://api.github.com/users/divega/events{/privacy}","received_events_url":"https://api.github.com/users/divega/received_events","type":"User","site_admin":false},"assignees":[{"login":"divega","id":1253414,"avatar_url":"https://avatars0.githubusercontent.com/u/1253414?v=4","gravatar_id":"","url":"https://api.github.com/users/divega","html_url":"https://github.com/divega","followers_url":"https://api.github.com/users/divega/followers","following_url":"https://api.github.com/users/divega/following{/other_user}","gists_url":"https://api.github.com/users/divega/gists{/gist_id}","starred_url":"https://api.github.com/users/divega/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/divega/subscriptions","organizations_url":"https://api.github.com/users/divega/orgs","repos_url":"https://api.github.com/users/divega/repos","events_url":"https://api.github.com/users/divega/events{/privacy}","received_events_url":"https://api.github.com/users/divega/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/milestones/2","html_url":"https://github.com/aspnet/EntityFrameworkCore/milestone/2","labels_url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/milestones/2/labels","id":648040,"number":2,"title":"Backlog","description":"Issues that have been approved but are not scheduled a specific release.","creator":{"login":"bricelam","id":1226749,"avatar_url":"https://avatars2.githubusercontent.com/u/1226749?v=4","gravatar_id":"","url":"https://api.github.com/users/bricelam","html_url":"https://github.com/bricelam","followers_url":"https://api.github.com/users/bricelam/followers","following_url":"https://api.github.com/users/bricelam/following{/other_user}","gists_url":"https://api.github.com/users/bricelam/gists{/gist_id}","starred_url":"https://api.github.com/users/bricelam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bricelam/subscriptions","organizations_url":"https://api.github.com/users/bricelam/orgs","repos_url":"https://api.github.com/users/bricelam/repos","events_url":"https://api.github.com/users/bricelam/events{/privacy}","received_events_url":"https://api.github.com/users/bricelam/received_events","type":"User","site_admin":false},"open_issues":599,"closed_issues":19,"state":"open","created_at":"2014-05-03T18:58:28Z","updated_at":"2018-04-19T22:46:18Z","due_on":null,"closed_at":null},"comments":2,"created_at":"2016-11-26T18:33:21Z","updated_at":"2018-04-19T22:46:18Z","closed_at":"2018-04-19T22:46:18Z","author_association":"NONE","body":"## Issue\r\n1) Type metadata management could be improved in EF.\r\n2) It is often the case where we create several classes (one per entity) simply to add display metadata to the properties of an entity.  A pain for very simple apps that don't require an additional layer of data abstraction beyond the EF models, with a few minor bad side effects like naming concerns.\r\n3) It is often the case where we copy/paste the same display metadata to several attributes because it is \"one of these things\".\r\n\r\n## Proposed\r\nBig Picture: Add \"Domains\" to the framework.\r\nCurrent:  Support a \"DataDomain\" property in DbContext/ModelBuilder and related classes/tooling.\r\n\r\n### Need Description\r\nI want to do something like this:\r\n\r\n```C#\r\npublic static class CustomerDataDomain{\r\n    public const string CommonName = \"Customer Name\"\r\n    public const string Display = \" [Display(Name =  \" + CommonName + \")]\";\r\n    public const int MaxInputLength = 48; // I'm saving some of the field length for unknown reasons...\r\n}\r\n```\r\nIn DbContext:\r\n```C#\r\nentity.Property(e => e.Person)\r\n    .HasDomain< CustomerDataDomain >() // This is the new feature\r\n    .IsRequired()\r\n    .HasColumnType(\"varchar(64)\");\r\n```\r\nIn ScaffoldingModelAnnotations it could automatically add the annotation to my model class to produce:\r\n\r\n```C#\r\n[Display(Name =  \"Customer Name\")]\r\n[MaxLength(48)]\r\npublic string Person { get; set; }\r\n```\r\nWith this feature I would be able to have EF generate \"ViewDataModels\" and well as Models:\r\n\r\nPM> Scaffold-DbContext \"connection\" Microsoft.EntitiyFrameworkCore.SqlServer -ViewData\r\n\r\n### Discussion\r\nElemental data is often \"MetaTyped\" very early in the analysis and design process. When I design my application, one of the things I start with are DataDomains. For example, I will create a Domain called Email, and I can assign a object representation (\"string\"), and database representation (\"varchar(128)\"). As I flush out my design I can just give new attributes or columns the type of \"Email\". If things change about the domain I just need to change one place. E.g., I can change Email to database=varchar(64), and all of the datatypes are changed for me. (I use modeling tools, so this is done for me). The thing about the domains is that they are really part of the item metadata and stay with the item through it's application layers, though it is interpreted differently by each layer. With Email, a string in the object, and varchar(128) in the data, and a set of css classes/jscripts in the presentation layer. In the Email case part of this concept is already there. There is even a build in DataAnnotation for it ([Email]) because it is so common. The large idea is that I should be able to assign the DataDomain in the database (e.g.) and if I ran scaffolding on DbContext and Controller it would influence the output of these tools.\r\n\r\nIt would be nice to be able carry something that exists beginning in the conceptual design stage and ending in the presentation layer all the way through the design/development tooling chain. Adding Domain concepts and DataDomains to EF would help. This would provide and additional layer of abstraction and information.\r\n\r\n### Concept\r\nThe conceptual idea is to add \"Domain\" to EF. Almost any EF item can have Domain related information, and there can be entire sets of capabilities around domains. Designers could create a set of Domain classes that would hold metadata about these areas. DataDomains could be just one.\r\n\r\n### Conceptual Overview\r\nIn looking at how this could be used we would first create an object and attributes called DataDomain in the Framework. Then using Fluent our Context could use:\r\n\r\n(Weak typed version)\r\n\r\n```C#\r\nentity.Property(e => e.Email)\r\n    .HasDomain(\"Email\")\r\n    .IsRequired()\r\n    .HasColumnType(\"varchar(128)\");\r\n```\r\nor\r\n(Strong type version)\r\n\r\n```C#\r\nentity.Property(e => e.Email)\r\n    .HasDomain< Email >(\"[Options]\")\r\n    .IsRequired()\r\n    .HasColumnType(\"varchar(128)\");\r\n```\r\n\r\nThis would then make something like .DataDomain... available on my objects  for me and for (importantly) tooling.\r\n\r\nWhen scaffolding entities EF could use (I don't know how this is actually done) a template like\r\n```C#\r\n[Display(Name = @Property.DataDomain.CommonName)]\r\npublic @Property.DataType Email....\r\n```\r\n### Use Cases\r\n#### Design-Time Use Case\r\nIf .DataDomain provides a const, it would be usable at design-time.\r\nAssuming for below cases we create classes that derive from a DataDomainBase class - \r\n\r\n```C#\r\npublic static class EmailDataDomain : DataDomainBase { \r\n  public const string DisplayName = \"Email Display Name\";\r\n}\r\n```\r\n#### Class Constant Use Case\r\nWe could use it like (for illustration)\r\n```C#\r\n[Display(Name =  EmailDataDomain.DisplayName)]\r\npublic string Person { get; set; }\r\n```\r\nThis gives us a simple way to use/reuse Domains.\r\n#### Class with [Display] Use Case\r\nVariations could include an overload of display that has a Domain parameter\r\n```C#\r\n[Display(Domain=typeof(EmailDataDomain)]\r\npublic string ContactEmail {get; set; }\r\n```\r\nThis exposes all of the properties to things like TagHelpers.\r\n#### Fully Integrated Use Case\r\nPromote \"Domain\" to create a framework-level DomainAttribute. This is preferred because is the most flexible with the broadest scope. It is also the most complicated and has major impact on the overall EF architecture.\r\n```C#\r\n[Domain(EmailDataDomain)] \r\npublic string ContactEmail { get; set; }\r\n```\r\n#### Fully-Fully Integrated Use Case\r\nImplemented as a service with a Domains Repository it could be injected, and a standard, extendable way to define Domains would be available.\r\n### Actions\r\nI propose two actions\r\n 1) first determine if the overall concept of Domains is valuable and if so start a design group around that. A goal would be to define DomainAttribute and how it would be used.  \r\n 2) Then (if so), prototype the concept by adding DataDomain where necessary to a fork to enable this simple (though weak and later disposable) experimental use:\r\n\r\n```C#\r\npublic static class CustomerDataDomain : IDataDomain {\r\n    public const string Display = [Display(Name =  \"Customer Name\")];\r\n}\r\n```\r\n\r\nIn DbContext:\r\n```C#\r\nentity.Property(e => e.Person)\r\n    .HasDomain(typeof(CustomerDataDomain))\r\n    .IsRequired()\r\n    .HasColumnType(\"varchar(128)\");\r\n```\r\nWhich would expose the DataDomain to scaffolding for use as Customer.DataDomain.Display.\r\n\r\n2.1) Modify Scaffold-DbContext to accept the -ViewModel switch. \r\n\r\nThis might be an early first step that cures a common pain point\r\n\r\n### Discussion Comment\r\nOne of the difficulties in doing this for the full chain is where to keep this in the data layer. In old SQL Server it could have been (hacked) in the Description field (maybe as json), but I'm not seeing Description in sys.syscolumns. Scaffolding would read and parse this to automatically add the .DataDomain<> to Context. \r\n"},"comment":{"url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/issues/comments/382903437","html_url":"https://github.com/aspnet/EntityFrameworkCore/issues/7132#issuecomment-382903437","issue_url":"https://api.github.com/repos/aspnet/EntityFrameworkCore/issues/7132","id":382903437,"user":{"login":"ajcvickers","id":1430078,"avatar_url":"https://avatars1.githubusercontent.com/u/1430078?v=4","gravatar_id":"","url":"https://api.github.com/users/ajcvickers","html_url":"https://github.com/ajcvickers","followers_url":"https://api.github.com/users/ajcvickers/followers","following_url":"https://api.github.com/users/ajcvickers/following{/other_user}","gists_url":"https://api.github.com/users/ajcvickers/gists{/gist_id}","starred_url":"https://api.github.com/users/ajcvickers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ajcvickers/subscriptions","organizations_url":"https://api.github.com/users/ajcvickers/orgs","repos_url":"https://api.github.com/users/ajcvickers/repos","events_url":"https://api.github.com/users/ajcvickers/events{/privacy}","received_events_url":"https://api.github.com/users/ajcvickers/received_events","type":"User","site_admin":false},"created_at":"2018-04-19T22:46:18Z","updated_at":"2018-04-19T22:46:18Z","author_association":"MEMBER","body":"Sorry for not responding in a long time on this. After discussing this again, we feel that this kind of functionality would be better implemented as extensions to the core EF code. Closing this as we don't plan to fix it in the main EF codebase."}}
{"actor":{"display_login":"ajcvickers"}}