// Hi everyone
i do this call in Action :
[HttpGet]
public virtual ActionResult JsonGetProvinces(int countryId)
{
//WebSiteContext WbContext = new WebSiteContext();
//UnitOfWork UnitofWork = new UnitOfWork(WbContext);
var provinces =
(
from province in unitofWork.ProvinceRepository.All
where province.CountryId == countryId
select new
{
Id = province.Id,
Name = province.GetType().GetProperty("Name_" + CultureManager.GetCurrentCultureShortName()).GetValue(province)
}
).ToList();
return Json(provinces, JsonRequestBehavior.AllowGet);
}
something is wrong with my query :
var provinces =
(
from province in unitofWork.ProvinceRepository.All
where province.CountryId == countryId
select new
{
Id = province.Id,
Name = province.GetType().GetProperty("Name_" + CultureManager.GetCurrentCultureShortName()).GetValue(province)
}
).ToList();
Particulary,
Name = province.GetType().GetProperty("Name_" + CultureManager.GetCurrentCultureShortName()).GetValue(province)
In BDD, there is Name_fr, Name_en columns
and i'm trying to take one dynamically... Is it possible ?
Of course, i can take both and choose dynamically the column in View but i would to know how do...
Thank you for your help
The short answer is you need to change your code a bit and using expression tree inside. Look at this question
EF can not translate function calls to SQL. Using expression trees can be comlicated see this question
Here is a sample with expression trees. The GetQuery2 is the same as GetQuery but with expression tree and a propertyname parameter.
public static IQueryable<Foo> GetQuery(BlogContext context)
{
var query = from x in context.BlogEntries
select new Foo
{
NameX = x.Name
};
return query;
}
public static IQueryable<Foo> GetQuery2(BlogContext context, string propertyName)
{
ConstructorInfo ci = typeof(Foo).GetConstructor(new Type[0]);
MethodInfo miFooGetName = typeof(Foo).GetMethod("set_NameX");
MethodInfo miBlogEntry = typeof(BlogEntry).GetMethod("get_" + propertyName);
ParameterExpression param = Expression.Parameter(typeof(BlogEntry), "x");
IQueryable<Foo> result = Queryable.Select<BlogEntry, Foo>(
context.BlogEntries,
Expression.Lambda<Func<BlogEntry, Foo>>(
Expression.MemberInit(
Expression.New(ci, new Expression[0]),
new MemberBinding[]{
Expression.Bind(miFooGetName,
Expression.Property(param,
miBlogEntry))}
),
param
)
);
return result;
}
It is easier the fetch all all language strings and write an additional Property Name that does the magic.
Related
I am able to get a somewhat dynamic Entity Framework search result with the following simplified example, which pulls a single result from the DB or Cache:
string strTableName = "TableName2"
string strColumnName = "MyColumnName"
int intPrimaryKey = 1
Type returnType;
returnType = typeof(TableName1);
string queryResults = null;
switch (strTableName)
{
case "TableName2":
returnType = typeof(TableName2);
break;
}
var refColumnName = returnType.GetProperty(strColumnName );
var query = mydbEntity.Set(returnType).Find(intPrimaryKey );
var queryResults = refColumnName.GetValue(query).ToString();
This can also be adapted for Updating a record:
DataQuery.LeadsEntity.Entry(query).Property(strColumnName ).CurrentValue = "Whatever";
DataQuery.LeadsEntity.SaveChanges();
Is there an equivalent for way for .set(returnType).Add()? I'm not sure if there is a way to do this type of thinking using variable table and column names:
DataQuery.LeadsEntity.Set(returnType).Add(new returnType { PrimayKeyName = 1, refColumnName = "Something" });
If you don't know a priori what's the name of the primary key property, it could be a little painful to get it from the type.
This is the way I found more reliable to retrieve the primary key from the entity type:
private string[] GetKeyNames(DbContext context, Type entityType)
{
ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
//create method CreateObjectSet with the generic parameter of the base-type
MethodInfo method = typeof(ObjectContext).GetMethod("CreateObjectSet", Type.EmptyTypes)
.MakeGenericMethod(entityType);
dynamic objectSet = method.Invoke(objectContext, null);
IEnumerable<dynamic> keyMembers = objectSet.EntitySet.ElementType.KeyMembers;
string[] keyNames = keyMembers.Select(k => (string)k.Name).ToArray();
_keyNamesCache[entityType] = keyNames;
return keyNames;
}
But assuming your primary keys are always a single property, you could use reflection to create the entity object and set its properties like this:
private void CreateEntity(Type entityType, object pkValue, Dictionary<string, object> Columns)
{
// Create the new entity
var entity = Activator.CreateInstance(entityType);
// Get the primary key property name
var pkName = GetKeyNames(context, entityType).First();
// Set Pk value
entityType.GetProperty(pkName).SetValue(entity, pkValue);
// Set other column(s)
foreach (var col in Columns)
{
entityType.GetProperty(col.Key).SetValue(entity, col.Value);
}
// Add the entity to the DbSet
using (var context = new YourContext())
{
context.Set(entityType).Add(entity);
}
}
Controller:
public ActionResult Univ(short id) {
var db = new DbEntities();
var query = from u in db.Universitates
join f in db.Facultates on u.IDUniv equals f.IDUniv
join s in db.Specializares on f.IDFac equals s.IDFac
where u.IDUniv == id
select new SearchViewModel
{
NumeUniv = u.NumeUniv,
OrasUniv = u.OrasUniv,
IDUniv = u.IDUniv,
NumeFac = f.NumeFac,
NumeSpec = s.NumeSpec
};
return View(query);
}
View:
#model Proj.Models.SearchViewModel
<h3>#Model.NumeUniv</h3>
I have the following error:
The model item passed into the dictionary is of type
'System.Data.Entity.Infrastructure.DbQuery`1[Proj.Models.SearchViewModel]',
but this dictionary requires a model item of type 'Proj.Models.SearchViewModel'.
Why is this?
The query is returning a enumerable list of SearchViewModel while your view is only looking for a single SearchViewModel.
Please try return View(query.First());
I'm trying to select all the rows out of a database using entity framework for manipulation before they're sent to the form
var ptx = [modelname].[tablename]();
ptx.[tablename].Select(????)
what goes in the ????
I used the entitydatasource and it provide everything I needed for what I wanted to do.
_repository.[tablename].ToList();
Entity Framework has one beautiful thing for it, like :
var users = context.Users;
This will select all rows in Table User, then you can use your .ToList() etc.
For newbies to Entity Framework, it is like :
PortalEntities context = new PortalEntities();
var users = context.Users;
This will select all rows in Table User
How about:
using (ModelName context = new ModelName())
{
var ptx = (from r in context.TableName select r);
}
ModelName is the class auto-generated by the designer, which inherits from ObjectContext.
You can use this code to select all rows :
C# :
var allStudents = [modelname].[tablename].Select(x => x).ToList();
You can simply iterate through the DbSet context.tablename
foreach(var row in context.tablename)
Console.WriteLn(row.field);
or to evaluate immediately into your own list
var allRows = context.tablename.ToList();
If it's under a async method then use ToListAsync()
public async Task<List<DocumentTypes>> GetAllDocumentTypes()
{
var documentTypes = await _context.DocumentTypes.ToListAsync();
return documentTypes;
}
Old post I know, but using Select(x => x) can be useful to split the EF Core (or even just Linq) expression up into a query builder.
This is handy for adding dynamic conditions.
For example:
public async Task<User> GetUser(Guid userId, string userGroup, bool noTracking = false)
{
IQueryable<User> queryable = _context.Users.Select(x => x);
if(!string.IsNullOrEmpty(userGroup))
queryable = queryable.Where(x => x.UserGroup == userGroup);
if(noTracking)
queryable = queryable.AsNoTracking();
return await queryable.FirstOrDefaultAsync(x => x.userId == userId);
}
Here is a few ways to do it (Just assume I'm using Dependency Injection for the DbConext)
public class Example
{
private readonly DbContext Context;
public Example(DbContext context)
{
Context = context;
}
public DbSetSampleOne[] DbSamples { get; set; }
public void ExampleMethod DoSomething()
{
// Example 1: This will select everything from the entity you want to select
DbSamples = Context.DbSetSampleOne.ToArray();
// Example 2: If you want to apply some filtering use the following example
DbSamples = Context.DbSetSampleOne.ToArray().Where(p => p.Field.Equals("some filter"))
}
You can use:
ptx.[tablename].Select( o => true)
I'm building/updating an EntityFramework EntityObject on runtime. I want to set the properties of the entity class, property names and values are coming from another source.
So I'm doing this;
public static EntityCollection<T> UpdateLocaleEntity<T>(EntityCollection<T> entityCollectionToUpdate, params ILocaleControl[] values) where T : EntityObject
{
foreach (var x in entityCollectionToUpdate)
{
Type t = typeof(T);
dynamic localeEntity = x;
string cultureCode = localeEntity.CultureCode;
for (int j = 0; j < values.Length; j++)
{
var value = values[j].GetLocaleValue(cultureCode);
t.GetProperty(values[j].EntityPropertyName).SetValue(localeEntity, value, null);
}
}
return entityCollectionToUpdate;
}
So, how can I get rid of "t.GetProperty(values[j].EntityPropertyName).SetValue(localeEntity, value, null);" part, is there a dynamic way of doing this?
Something like;
dynamicCastedLocaleEntity.GetProperty(values[j].EntityPropertyName) = value;
Thanks.
Long answer coming up.
Reflection is great in many situations, horrible in some but in almost all cases it's slow.
There are at least 4 different ways to set a property in .NET without having to use reflection.
I thought I demonstrate one of them: Using compiled expression trees. Note that the expression building is rather expensive too so that's why it's very important to cache the delegate one builds with it in a dictionary (for instance):
Expression Trees was introduced in .NET35 and is used for many things. Here I use them to build a property setter expression and then compile it into a delegate.
The example demonstrates different timing for the different cases but here are my numbers:
Control case (hard coded): 0.02s
Reflection: 1.78s
Expression Tree: 0.06s
using System;
using System.Linq.Expressions;
namespace DifferentPropertSetterStrategies
{
class TestClass
{
public string XY
{
get;
set;
}
}
class DelegateFactory
{
public static Action<object, object> GenerateSetPropertyActionForControl(
)
{
return (inst, val) => ((TestClass) inst).XY = (string) val;
}
public static Action<object, object> GenerateSetPropertyActionWithReflection(
Type type,
string property
)
{
var propertyInfo = type.GetProperty(property);
return (inst, val) => propertyInfo.SetValue (inst, val, null);
}
public static Action<object,object> GenerateSetPropertyActionWithLinqExpression (
Type type,
string property
)
{
var propertyInfo = type.GetProperty(property);
var propertyType = propertyInfo.PropertyType;
var instanceParameter = Expression.Parameter(typeof(object), "instance");
var valueParameter = Expression.Parameter(typeof(object), "value");
var lambda = Expression.Lambda<Action<object, object>> (
Expression.Assign (
Expression.Property (Expression.Convert (instanceParameter, type), propertyInfo),
Expression.Convert(valueParameter, propertyType)),
instanceParameter,
valueParameter
);
return lambda.Compile();
}
}
static class Program
{
static void Time (
string tag,
object instance,
object value,
Action<object, object > action
)
{
// Cold run
action(instance, value);
var then = DateTime.Now;
const int Count = 2000000;
for (var iter = 0; iter < Count; ++iter)
{
action (instance, value);
}
var diff = DateTime.Now - then;
Console.WriteLine ("{0} {1} times - {2:0.00}s", tag, Count, diff.TotalSeconds);
}
static void Main(string[] args)
{
var instance = new TestClass ();
var instanceType = instance.GetType ();
const string TestProperty = "XY";
const string TestValue = "Test";
// Control case which just uses a hard coded delegate
Time(
"Control",
instance,
TestValue,
DelegateFactory.GenerateSetPropertyActionForControl ()
);
Time(
"Reflection",
instance,
TestValue,
DelegateFactory.GenerateSetPropertyActionWithReflection (instanceType, TestProperty)
);
Time(
"Expression Trees",
instance,
TestValue,
DelegateFactory.GenerateSetPropertyActionWithLinqExpression(instanceType, TestProperty)
);
Console.ReadKey();
}
}
}
For FuleSnabel's answer, you can speed it up a lot (sometimes twice as fast in my tests). In some tests, it was just as fast as the Control solution:
public static Action<Object,Object> GenerateSetPropertyActionWithLinqExpression2(Type type, String property) {
PropertyInfo pi = type.GetProperty(property,BindingFlags.Instance|BindingFlags.Public);
MethodInfo mi = pi.GetSetMethod();
Type propertyType = pi.PropertyType;
var instance = Expression.Parameter(typeof(Object), "instance");
var value = Expression.Parameter(typeof(Object), "value");
var instance2 = Expression.Convert(instance, type);
var value2 = Expression.Convert(value, pi.PropertyType);
var callExpr = Expression.Call(instance2, mi, value2);
return Expression.Lambda<Action<Object,Object>>(callExpr, instance, value).Compile();
}
possibly not with EntityObject, but if you've had an ExpandoObject than you can do
dynamic entity = new ExpandoObject();
(entity as IDictionary<String, Object>)[values[j].EntityPropertyName] = value
The open source framework ImpromptuInterface has methods to invoke based on a string using the DLR rather than reflection and runs faster than reflection too.
Impromptu.InvokeSet(localeEntity, values[j].EntityPropertyName,value);
I'm afraid not. Any use of a dynamic object is baked-in at compile time. Any call which could vary at run-time has to be done using reflection.
private List<T> GetFieldList()
{
var Fields = new { DisplayName = "MCP", FieldName = "t.MCP", FieldType = 1 };
var FieldList = (new[] { Fields }).ToList();
return FieldList;
}
Should I be able to do something like this?
If I understand correctly your tag "asp.net" this construction will be used as part of data binding.
Just use non generic :
private IList GetFieldList()
{
var Fields = new { DisplayName = "MCP", FieldName = "t.MCP", FieldType = 1 };
IList FieldList = (new[] { Fields }).ToList();
return FieldList;
}
It would be nice handled by all data-bound controls.
I just realized I don't need to use an anonymous list as I know the structure of the data I'm expecting, so I'll just create a small class for it.