Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata - Providers (and the default Fluent API) #2

Open
andrerpena opened this issue Jan 5, 2015 · 5 comments
Open

Metadata - Providers (and the default Fluent API) #2

andrerpena opened this issue Jan 5, 2015 · 5 comments

Comments

@andrerpena
Copy link
Contributor

Gearz applications get metadata through classes that implement the IMetadataProvider interface. It's possible to implement providers that obtain metadata from a variaty of sources, including JSON, XML, databases and so forth. However, the recommended provider for the majority of applications is the FluentMetadataProvider, that allows you to define metadata in a type-safe way.

The FluentMetadataProvider class exposes a fluent API that is very simillar to Entity Framework.

Example:

public class FluentMetadataProvider : IMetadataProvider
{
    /// <summary>
    /// Sets up the application metadata using the given metadata context
    /// </summary>
    /// <param name="meta"></param>
    public void SetupMetadata(MetadataContext meta)
    {
        // configuring contacts
        meta.Entity<Contact>().Property(c => c.Name).Required(true).MaxLength(30);
        meta.Entity<Contact>().Property(c => c.DateOfBirth).Required(true);
    }
}

How it works

Calling the Entity() function defines that an entity existis. Subsequent calls will have no effect. The same is truth for properties as well. For instance, the line:

meta.Entity<Contact>().Property(c => c.Name).Required(true).MaxLength(30);

Is defining that Contact exists as an Entity, that it has a property called Name, and that property is required and it's max length is 30.

@andrerpena
Copy link
Contributor Author

@masbicudo , I am not really sure about what how to implement this fluent API.

In Entity Framework, there's no AddEntity or AddProperty, because all entities that are present in the DbContext are already added, and all properties of the entities are also added automatically.. So the API is not about adding, it's about giving metadata to something that has been added already.

However, Gearz doesn't work that way. There's no DbContext so the entities must explicitly be added. Furthermore, in the entity views, the order does matter, so you need to explicitly add properties in a particular order (this is not valid for entities).

However, things are less fluent with Add functions.. because once added, it doesn't make sense to call add again.

So I think that entities and properties should be implicitly added when you reference tem.. like this:

meta.Entity();

The above line is all it takes to add a Contacts entity. If I reference it again, it will just take the previously added contact, not add a new one..

meta.Entity<Contact>().Property(c => Name);

The above line states that Contact, that has been implicitly added before, has a property called Name.

If we want to make it required.. We can put this in another line (or in the same):

meta.Entity<Contact>().Property(c => Name).IsRequired();

All metadata inside Property returns this.. So it's possible to do this:

meta.Entity<Contact>().Property(c => Name).IsRequired().IsInvalid().IsSomethingElse();

@masbicudo
Copy link
Member

I think that repetitions should be avoided:

meta.Entity<Contact>(ctx => {
    ctx.Property(c => c.Name).IsRequired();
    ctx.Property(c => c.Other).IsRequired().IsInvalid().IsSomethingElse();
})

Or making a generic interface:

public class FluentMetadataProvider :
    IMetadataProvider<Contact>,
    IMetadataProvider<Xpto>
{
    public void SetupMetadata(MetadataContext<Contact> meta)
    {
        meta.Property(c => c.Name).Required(true).MaxLength(30);
        meta.Property(c => c.DateOfBirth).Required(true);
    }

    public void SetupMetadata(MetadataContext<Xpto> meta)
    {
        meta.Property(c => c.PropA).Required(true).MaxLength(30);
        meta.Property(c => c.PropB).Required(true);
    }
}

If that doesn't look good, then I'm fine with repeated things. As you said, the method is to state that something exist, not to add it.

Another great idea would be just to reuse the definitions given by other frameworks, such as EntityFramework or nHibernate, as these entities are going to be handled by a persistence layer anyway... the objective is to make things less repetitive... so, if we can make EFMetadataProvider and NHMetadataProvider it would be nice.

Of course these would be in different projects (so that we can make nuget packages for them separately)

@andrerpena
Copy link
Contributor Author

I agree with the non-repetitive thinking.

Actually I think I liked the idea of separating metadata provider for each of the entities.. We'd have to think about it more thoughly.. but the advantage is that, given that IMetadataProvider<Contact> exists and has been added to a collection, it means Contact exists as an entity.. you don't have to manually add it.

We could have an interface for the overall metadata provider, like IMetadataProvider and an interface for each entity, like IEntityMetadataProvider<T>.

I'm also kin of the idea of adding each IEntityMetadataProvider<T> to the IMetadataProvider explicitly. That is, not discovering IEntityMetadataProvider implementations automatically.

@masbicudo
Copy link
Member

We could rename this isse to Metadata - Providers, so that we can discuss them more broadly. Then we can continue the discussion about providers from the other proposal Metadata - Text-expressions... about ORM providers, Xml providers and all sorts, here.

Do you agree?

@andrerpena
Copy link
Contributor Author

Sure

@masbicudo masbicudo changed the title Metadata - Fluent API Metadata - Providers (and the default Fluent API) Jan 21, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants