linq2db how to iterate over Properties in Fluent Mapping? - c#

I am using the ORM linq2db.
We have the need to set the column names at runtime.
That's why I can't use the attributes in the POCO-Class and instead use the Fluent Mapping Api (which is not documented as far as I know).
Because the column names will be determined at runtime I want to iterate over all properties in my Entities and set the Columnname.
In EF Core 3.x this would look like something like this:
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties()))
{
property.SetColumnname(columnNameDict[property.Name]);
}
Is there a possibility to iterate over all the Properties in my Model, like in EF Core?
In linq2db to set the properties of a Property I have to use code like this:
builder
.Entity<Addresses>()
.HasTableName("ADDRESSES")
.Property(x => x.Company) // This is the Membergetter, which i can't use in a foreach afaik.
.HasColumnName("TEXT1")
To Access the Property ID I have to use "x => x.ID"(Expression<Func<Addresses, object>> memberGetter), but when I Iterate over the Properties, I don't know how to select the correct Property (PropertyMappingBuilder) without using this Expression (memberGetter) or how to set this Expression in a foreach. Is there a string overload like this .Property("Company")? I coudn't find any.
I tried it with reflection, but the Expression part didn't work ;):
foreach (var property in typeof(Addresses).GetProperties())
{
var fieldInfo = adressenInfo.GetFieldByUser(property.Name);
adressenBuilder.Property(a => property.GetValue(a)) // this line doesn't work
.HasColumnName(fieldInfo.LogicalName)
.HasDbType(fieldInfo.DataBaseType);
}
Any Ideas are welcome! Thanks :)

You need to generate proper LambdaExpression manually for Parameter() method.
var param = Expression.Parameter(typeof(Addresses));
adressenBuilder.Property(Expression.Lambda<Func<Addresses, object>>(
Expression.Convert(Expression.Field(param, fieldInfo), typeof(object)),
param))...

Related

How do you check if a property has IsRequired() on an object using reflection?

I have a string property it is configured as IsRequired() using FluentAPI. How do I check if this property is required? I'm iterating through all properties of my object using reflection.
It is not possible to achieve this via reflection cause Fluent API does not emit any CLR type data (if you have used data annotations it would be quite trivial just by looking for corresponding attributes on properties). You will need to examine the Model property of the context or EntityType of the DbSet to get this metadata. Something along this lines, for example:
// var entityType = ctx.Model.GetEntityTypes()
// .Where(type => type.ClrType == typeof(Person))
// .First();
// or
var entityType = ctx.Persons.EntityType;
var property = entityType.FindProperty("PrimaryAddressId");
var required = !property.IsNullable;

Convert IEnumerable<T> to collection of dynamically generated objects

Recently I asked a more general question about getting properties of model through foreign key.
Now I moved a bit further but still have no idea how transform objects on the fly.
What I've got is an IEnumerable collection which I get through repository
regionRaw = unitOfWork.RegionRepository.Get(
keyOrder: q => q.OrderBy(d => d.RegionID),
filter: p => p.FullName.Contains(lastname) || p.ShortName.Contains(lastname),
orderBy: jtSorting,
includeProperties: "District, ISO31662, GOST767Region");
Further I am going to export data from this collection to Excel. So I need a select statement that gets all the fields I need.
dt = regionRaw
.Select(x => new
{
ISO = x.ISO31662.GOSTName,
DistrictName = x.District.ShortName
})
I do not want to enumerate all the fields I need like on the top.
I am able to make a method that recognizes which of the fields have simple values and which have objects referenced through foreign key. And then that method will return a list of properties.
Now I need some way to write something like a foreach inside select. I see something like this:
dt = regionRaw
.Select(x => new
{
foreach (prop in propList)
{
prop.PropertyName = x.GetType()
.GetProperty(prop.TableName)
.GetValue(x, null).GetType()
.GetProperty(prop.PropertyName)
.GetValue(
x.GetType().GetProperty(prop.TableName).GetValue(x, null),
null);
}
}
Where propList is a collection of properties that I get before.
I do totally realize that upper code is more a pseudo-code but I have no idea how to realize this in .NET.
So if you can suggest some solution for this task I will be very grateful. Or maybe you could explain that all this is a bad idea and shouldn't be realized.
You wont be able to create an anonymous type with dynamic properties as anon types are created during compile and your properties are created during execution.
But why do you need strongly typed properties if you're not going to code against them, as you wont know them until someone executes the query?
Expando object may be of use to you?http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx

Create expression from reflected type

I have a method signature like this:
IPostprocessComposer<T> Without<TProperty>(Expression<Func<T, TProperty>> propertyPicker)
Example usage:
AutoFixture.Build<Request>()
.Without(p => p.ID)
.Create();
I want to create a more flexible solution and always ignore a few properties from the type (in this case "Request") identified via reflection
My (not working) solution:
IPostprocessComposer<T> row = fixture.Build<T>();
var primitivePropertiesToIgnore = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.Name.ToLowerInvariant().StartsWith("id") || p.Name.ToLowerInvariant().EndsWith("id"));
foreach (var primitiveProperty in primitivePropertiesToIgnore)
{
var x = Expression.Parameter(typeof(T));
var expr = Expression.Lambda(Expression.PropertyOrField(x, primitiveProperty.Name), x);
// This line is working, but of course I need "int" to be a generic type here... how can i achieve this?
row = row.Without((Expression<Func<T, int>>)expr);
}
Question:
I guess the expression must be somehow differently passed to the Without method in order to work? But how?
The simplest way to make this work is to use dynamic:
row = row.Without((dynamic)expr);
Since row is already statically typed, the dynamic behavior will be contained to only this statement.
If you didn't want to use dynamic, you would need to use reflection to invoke the Without method with the right type parameters, but I don't see any advantage in doing that (it's more complicated, but it isn't any more type-safe).

linq lambda expression; get EF object and remove selected properties

I have a single instance of an object:
AS_SYSTEM system = ctx.AS_SYSTEM.Where(s => s.SYSTEM_ID == query).First();
And i want to remove some properties from it. All properties that ends with "Reference". Something like
system.GetType().GetProperties().Name.EndsWith("Reference")
I want to remove all ef properties that are linked to other tables.
To nullify (the values) of all properties ending with 'Reference', using reflection:
var properties = system.GetType().GetProperties().Where(x => x.Name.EndsWith("Reference"));
foreach (var p in properties)
{
p.SetValue(system, null, null);
}
Though I'm not sure that you really need to use reflection here, thats how its done.

How to get all names of properties in an Entity?

What I'm trying to do is to pass an entity object to method and return all the names of the properties in it.
I'm using this code to get all the props names :
return classObject.GetType().GetProperties();
The problem is that this code return "EntityKey" and "EntityState" as properties whe I use it with Entity Object.
Is there any way to do it ?
Thanx in advance
You want all direct properties, but not the properties of the base type, which in your case is EntityObject:
var type = classObject.GetType();
//alternatively call out directly: typeof(EntityObject).GetProperties()...
var basePropertyNames = type.BaseType.GetProperties().Select(x => x.Name);
var props = type.GetProperties().Where(p => !basePropertyNames.Contains(p.Name));
This sample assumes there is a base type (which is the case for DB first), refactor when that is not guaranteed.
Edit from #Matt's comment: All of the above is unnecessary, could slap my head for not thinking of this - just use the right binding flags:
return classObject.GetType().GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
It is also possible without reflection:
using (var context = new ModelContainer())
{
// Access CSDL
var container = context.MetadataWorkspace
.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
// Access name of related set exposed on your context
var set = container.BaseEntitySets[context.YourEntitySet.EntitySet.Name];
// Access all properties
var properties = set.ElementType.Members.Select(m => m.Name).ToList();
// Access only keys
var keys = set.ElementType.KeyMembers.Select(m => m.Name).ToList();
}
As you can see you have access to much more then names. The example shows that you can now which property is part of key. If you access Members directly you can know which property is scalar, complex type or navigation property.
All information are already loaded so there is no need for reflection. If you want to use reflection don't forget to use it only once (first time you need it) and then store and reuse received property names. Reflection is slow so using it each time you need names is a bad practice.
I had the same problem. The solution I found was to create an array with the name of the properties to return (I olnly need a few). In your case, since it can be laborious to keep track of all properties, I would filter the properties EntityKey and EntityState and return all the others. The code would be something like this:
public IEnumerable<PropertyInfo> GetProperties()
{
Type t = this.GetType();
return t.GetProperties()
.Where(p => (p.Name != "EntityKey" && p.Name != "EntityState"))
.Select(p => p).ToList();
}
Don't know if there is a better solution, but it would be nice ;) Hope it helps!
As stated by BrokenGlass but beware if you need performance and you want to do this in loops. Reflection is not a fast thing.
If you need performance you may wish to put a virtual method in your base class to retrieve the properties as an array of strings or whatever, and override that in all derived classes. This would be the fastes approach but with more coding.

Categories

Resources