How do you model custom attributes of entities?
The grouping is not going to be easy because what aggregate operator are you going to use on "color"? Note that it is not possible to use your requirement 4 on case 2.
In any case, the aggregating is only difficult because of the variation in data types and can be mitigated by approaching it in a more typesafe way - knowing that it never makes sense to add apples and oranges.
This is the classic EAV model and it has a place in databases where carefully designed. In order to make it a bit more typesafe, I've seen cases where the values are stored in type-safe tables instead of in a single free form varchar column.
Instead of Values:
EntityID int
,AttributeID int
,Value varchar(255)
You have multiple tables:
EntityID int
,AttributeID int
,ValueMoney money
EntityID int
,AttributeID int
,ValueInt int
etc.
Then to get your iPod capacity per generation:
SELECT vG.ValueVarChar AS Generation, SUM(vC.ValueDecimal) AS TotalCapacity
FROM Products AS p
INNER JOIN Attributes AS aG
ON aG.AttributeName = 'generation'
INNER JOIN ValueVarChar AS vG
ON vG.EntityID = p.ProductID
AND vG.AttributeID = aG.AttributeID
INNER JOIN Attributes AS aC
ON aC.AttributeName = 'capacity'
INNER JOIN ValueDecimal AS vC
ON vC.EntityID = p.ProductID
AND vC.AttributeID = aC.AttributeID
GROUP BY vG.ValueVarChar
What is the best approach for users to add custom attributes to entities?
I favor adding fields to a table via DDL, but that table should be separate from the main table. That way, you can script changes to your database schema without affecting your users' custom field additions. A right-join is easy enough to accomplish, and you won't need the record in the separate table if there are no custom fields.
If you just want to display data in a vertical fashion, EAV tables can be a good choice. You can also run a pivot query to display them horizontally.
Adding custom property attributes in Entity Framework code
You can do this by specifying a metadata type that mirrors the properties and is used simply for attribution.
[MetadataType(typeof(Dinner_Validation))]
public partial class Dinner
{}
public class Dinner_Validation
{
[Required]
public string Title { get; set; }
}
Steve Smith blogs about it here.
Unfortunately the above approach is brittle to refactoring. Another option is to use the new POCO entities. These avoid compile-time code generation altogether as far as I can tell. I haven't used them yet so can't comment on any pitfalls or tradeoffs.
Using a custom attribute in EF7 (core) OnModelCreating
EF Core knows nothing about your custom attribute, so there is no way it to be discovered and exposed as annotation (which in general is a different thing and not necessarily associated with attribute).
You have to extract the attribute manually from PropertyInfo
or FieldInfo
when present:
foreach (var entityType in builder.Model.GetEntityTypes())
foreach (var property in entityType.GetProperties())
{
var memberInfo = property.PropertyInfo ?? (MemberInfo)property.FieldInfo;
if (memberInfo == null) continue;
var defaultValue = Attribute.GetCustomAttribute(memberInfo, typeof(DefaultAttribute)) as DefaultAttribute;
if (defaultValue == null) continue;
if (defaultValue.UseAsLiteral)
property.Npgsql().DefaultValueSql = defaultValue.DefaultValue.ToString();
else
property.Npgsql().DefaultValue = defaultValue.DefaultValue;
}
Custom attributes on EF code-first models
In EF6 you can use the command interception mechanism where the interceptor is invoked each time the command is being executed. You can also modify results if needed (might be a bit cumbersome though). This article is a good starting point. Another way to go about it is to look at the ObjectContext.ObjectMaterialized event and populate properties that are not populated by EF in the handler for this event.
Related Topics
Informix 7.3 Isql Insert Statement - Text/Blob/Clob Field Insert Error
Jooq - Support for Update ... Set ... Query with Arbitrary Degree
Index on Timestamp: Functions in Index Expression Must Be Marked as Immutable
Join Four Tables Involving Left Join Without Duplicates
Query the Two Cities in Station with the Shortest and Longest City Names,
Mysql: Select N Rows, But with Only Unique Values in One Column
Besides a Declarative Language, Is SQL a Functional Language
Update Xml Tag in a Clob Column in Oracle
Access 2007: "Select Count(Distinct ..."
How to Make a Sum Without Group By
Sqlite Create Pre-Populated Fts Table
How to Release Possible Postgres Row Locks
Transfer Data Between Databases with Postgresql
Fetch a Record on Maximum Date of Every Month
How to Create a One-Time-Use Function in a Script or Stored Procedure