How to Model Custom Attributes of Entities

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



Leave a reply



Submit