redis-om-dotnet icon indicating copy to clipboard operation
redis-om-dotnet copied to clipboard

Fluent API instead of attributes

Open iozcelik opened this issue 2 years ago • 12 comments

When writing entities, I do not prefer to use attributes too much. After release of ef core fluent API, I prefer it. And not only me, lots of .net developer prefer same.

I advice to redis om .net adds an alternative usage for fluent api.

Cuurent usage:

var provider = new RedisConnectionProvider("redis://localhost:6379");
var connection = provider.Connection;
var people = provider.RedisCollection<Person>();
connection.CreateIndex(typeof(Person));

[Document(StorageType = StorageType.Json, IndexName = "person-idx")]
public class Person {
    [RedisIdField]
    [Indexed]
    public string Id { get; set; }
    [Searchable]
    public string Name { get; set; }

    [Indexed(Sortable = true)]
    public int? Age { get; set; }

    [Indexed(Sortable = true)]
    public double? Height { get; set; }

    [Indexed(Sortable = true)]
    public int? DepartmentNumber { get; set; }

    [Indexed(Sortable = true)]
    public double? Sales { get; set; }

    [Indexed(Sortable = true)]
    public double? SalesAdjustment { get; set; }
}

I prefer something like that:

public class PersonEntityTypeConfiguration : IRedisCollectionConfiguration<Person> {
    public void Configure(RedisCollectionTypeBuilder<Person> builder) {
        builder.StorageType(StorageType.Json);
        builder.Property(b => b.Id).IsIndexed().IsRedisIdField();
        builder.Property(b => b.Name).IsSearchable();
        builder.Property(b => b.Age).IsIndexed(sortable:true);
        builder.Property(b => b.Height).IsIndexed(sortable:true);
        builder.Property(b => b.DepartmentNumber).IsIndexed(sortable:true);
        builder.Property(b => b.Sales).IsIndexed(sortable:true);
        builder.Property(b => b.SalesAdjustment).IsIndexed(sortable:true);
        builder.HasIndex(typeof(Person), "person-idx");
    }
}


var provider = new RedisConnectionProvider("redis://localhost:6379");
var connection = provider.Connection;

provider.AddRedisCollectionConfiguration<PersonEntityTypeConfiguration>();


var people = provider.RedisCollection<Person>();

public class Person {
    public string Id { get; set; }
    public string Name { get; set; }
    public int? Age { get; set; }
    public double? Height { get; set; }
    public int? DepartmentNumber { get; set; }
    public double? Sales { get; set; }
    public double? SalesAdjustment { get; set; }
}

iozcelik avatar Sep 09 '22 07:09 iozcelik

Hi @iozcelik - that's a pretty radical departure from how the library was built and would be a really substantial amount of effort (rebuilding the expression parsing logic, the index serialization logic, basically every test would need to be duplicated, reworking all the docs, etc. . .). There are both gains and drawbacks to both approaches, they are probably about equivalent on balance, with the primary differentiator most likely being a matter of taste, so I'm not sure I could justify the time required to build this.

slorello89 avatar Sep 09 '22 12:09 slorello89

Hi @slorello89 , I design a new library and it has both version lite and normal. Lite version has not redis support, it uses .net memory cache and it is enough because it has single node.

However, normal version is distibuted system. Uses same classes with lite version. So in this case, I use redis. So for this basic scenario (I have complex scenarios also :)), fluent api better than attributes. I add necessary packages only if required.

I try to handle of course with my way. But native support could be better.

iozcelik avatar Sep 09 '22 13:09 iozcelik

Hi @iozcelik, One thing you can try is a feature I use within Service Stack Framework - Dynamically adding Attributes

typeof(MyPoco)
    .AddAttributes(new DataContractAttribute())
    .GetProperty(nameof(MyPoco.LastName))
    .AddAttributes(new DataMemberAttribute { Name = "Surname" });

Possibly you could use something like this to wire up the attributes in a Builder type method that gives you what you need?

VagyokC4 avatar Sep 09 '22 23:09 VagyokC4

Hi @VagyokC4 , yes probably I use like this one. Also, probably, I write a wrapper for redis :)

iozcelik avatar Sep 10 '22 01:09 iozcelik

That new proposed format reminds me of how HotChocolate (.NET library for GraphQL) uses for defining GraphQL object type

frostshoxx avatar Sep 13 '22 17:09 frostshoxx

+1 for this. I have an existing app that I would where like to build a new persistence provider that uses Redis OM but I can't add attributes (or the Nuget dependency) to the existing core product. I would like to isolate it into the persistence provider assembly.

The only way I can find to do that now is to map all of the existing domain objects into new DTOs for persistence.

MarkEwer avatar Oct 26 '23 18:10 MarkEwer

ITNOA

Hi,

@slorello89

  • What is state of this feature?
  • Do you start developing?
  • Do you accept PR for this feature?
  • Any specific criteria or specific design to be consider for this feature?

thanks

soroshsabz avatar Feb 15 '24 14:02 soroshsabz

Hi @soroshsabz, IMO there's pretty robust and consistent demand for this feature, so it's something I'd like to do. I haven't started developing it, but I'd like it to look somewhat similar to the fluent api that EF provides for model building. It's a major undertaking though and I don't currently have a timeline.

slorello89 avatar Feb 15 '24 14:02 slorello89

So do you accept PR for this?

soroshsabz avatar Feb 15 '24 14:02 soroshsabz

+1 for this for helping dotnet community writing cleaner code

Using attributes forces developers to add external services dependency to domain core project Fluent API design promotes loose coupling and separation of concerns between the domain and infrastructure layers.

AhmadAlMunajjed avatar May 17 '24 07:05 AhmadAlMunajjed

Any plans to implement it in the near future?

We have no option but to add redis-om-dotnet Nuget dependency to our domain for now. We really appreciate considering this feature.

To achieve the separation of concerns between the domain and infrastructure layers, in additional to Fluent Api, we need the Async methods to be written as extension methods to Iqueryable instead of implemeting it for IRedisCollection

AhmadAlMunajjed avatar May 17 '24 07:05 AhmadAlMunajjed