Return rows from stored procedure - entity-framework

I have this code:
public IEnumerable<SomeClass> GetAvalibleThingies(DateTime startDate, DateTime endDate, int categoryID)
{
if (_entities.Connection.State == System.Data.ConnectionState.Closed)
_entities.Connection.Open();
using (EntityCommand c = new EntityCommand("SomeEntities.GetAvalibleThingies", (EntityConnection)this._entities.Connection))
{
c.CommandType = System.Data.CommandType.StoredProcedure;
EntityParameter paramstartDate = new EntityParameter("startDate", System.Data.DbType.DateTime);
paramstartDate.Direction = System.Data.ParameterDirection.Input;
paramstartDate.Value = startDate;
c.Parameters.Add(paramstartDate);
........
var x = c.ExecuteReader();
return x as IEnumerable<SomeClass>;
};
But I can't get it to return a list of SomeClass. What's needed to do here? I use the entity framework 3.5sp1 one
/M

EntityDataReader is a class similar to SqlDataReader and should be handled in the similar way.
Instead of the lines
var x = c.ExecuteReader();
return x as IEnumerable;
should be something like
List list = new List();
using(EntityDataReader reader = c.ExecuteReader()) {
while(reader.Read()) {
SomeClass item = new SomeClass() {
};
list.Add(item);
}
}
return list;

Related

Entity Framework - LINQ - Use Expressions in Select

I am using within my code some EF LINQ expressions to keep complex queries over my model in one place:
public static IQueryable<User> ToCheck(this IQueryable<User> queryable, int age, bool valueToCheck = true)
{
return queryable.Where(ToBeReviewed(age, valueToCheck));
}
public static Expression<Func<User, bool>> ToCheck(int age, bool valueToCheck = true)
{
return au => au.Status == UserStatus.Inactive
|| au.Status == UserStatus.Active &&
au.Age.HasValue && au.Age.Value > age;
}
I am then able to use them in queries:
var globalQuery = db.Users.ToCheck(value);
And also in selects:
var func = EntityExtensions.ToCheck(value);
var q = db.Department.Select(d => new
{
OrdersTotal = d.Orders.Sum(o => o.Price),
ToCheck = d.Users.AsQueryable().Count(func),
})
What I am trying to achieve is to actually use the same expression/function within a select, to evaluate it for each row.
var usersQuery = query.Select(au => new {
Id = au.Id,
Email = au.Email,
Status = au.Status.ToString(),
ToBeChecked = ???, // USE FUNCTION HERE
CreationTime = au.CreationTime,
LastLoginTime = au.LastLoginTime,
});
I am pretty that threre would be a way using plain EF capabilities or LINQKit, but can't find it.
Answering my own question :)
As pointed by #ivan-stoev, the use of Linqkit was the solution:
var globalQueryfilter = db.Users.AsExpandable.Where(au => au.Department == "hq");
var func = EntityExtensions.ToCheck(value);
var usersQuery = globalQueryfilter.Select(au => new
{
Id = au.Id,
Email = au.Email,
Status = au.Status.ToString(),
ToBeChecked = func.Invoke(au),
CreationTime = au.CreationTime,
LastLoginTime = au.LastLoginTime,
});
return appUsersQuery;
It's required to use the AsExpandable extension method from Linqkit along with Invoke with the function in the select method.
I want to add one more example:
Expression<Func<AddressObject, string, string>> selectExpr = (n, a) => n == null ? "[no address]" : n.OFFNAME + a;
var result = context.AddressObjects.AsExpandable().Select(addressObject => selectExpr.Invoke(addressObject, "1"));
Also, expression can be static in a helper.
p.s. please not forget to add "using LinqKit;" and use "AsExpandable".

How do you create Expression<Func<T, T>> given the property names of T to map?

Here's what the required function would look like:
public static Expression<Func<T, T>> GetExpression<T>(string propertyNames) where T : class
{
var properties = propertyNames.Split(
new char[] { ',' },
StringSplitOptions.RemoveEmptyEntries
).ToList();
//need help here
}
Currently I'm doing it like this:
_context.Questions.Select(q =>
new Question() {
QuestionId = q.QuestionId,
QuestionEnglish = q.QuestionEnglish
}
).ToList();
And I want to replace it with:
_context.Questions.Select(GetExpression<Question>("QuestionId, QuestionInEnglish")).ToList();
Any help would be greatly appreciated.
You can do it like this;
public static Func<T, T> GetExpression<T>(string propertyNames)
{
var xParameter = Expression.Parameter(typeof(T), "parameter");
var xNew = Expression.New(typeof(T));
var selectFields = propertyNames.Split(',').Select(parameter => parameter.Trim())
.Select(parameter => {
var prop = typeof(T).GetProperty(parameter);
if (prop == null) // The field doesn't exist
{
return null;
}
var xOriginal = Expression.Property(xParameter, prop);
return Expression.Bind(prop, xOriginal);
}
).Where(x => x != null);
var lambda = Expression.Lambda<Func<T, T>>(Expression.MemberInit(xNew, selectFields), xParameter);
return lambda.Compile();
}
Usage;
var list = new List<Question>{new Question{QuestionEnglish = "QuestionName",QuestionId = 1}};
var result = list.Select(GetExpression<Question>("QuestionId, QuestionEnglish"));

GroupBy Clause: To be able to pass in a Column name as a string

In EF, Order By allows a column name to be used to eg OrderBy("Description")
I need to be able to do some thing similar with GroupBy
Other posts have solutions when the column type is known
var groupByExpressionGN2 = GetGroupByExpressionGuidNull<DebtWaiver>("PersonUID");
...
// in the query
.GroupBy(groupByExpression2)
// the Expression function
private static Expression<Func<TEntity,Guid?>> GetGroupByExpressionGuidNull<TEntity>(string property)
{
var item = Expression.Parameter(typeof(TEntity), "gb");
var itemProperty = Expression.PropertyOrField(item, property);
var lambda = Expression.Lambda<Func<TEntity, Guid?>>(itemProperty, item);
return lambda;
}
But my users may select 1 of any columns by which to group by
So how can I make the function above return an expression for group by
I have tried this:
public static Expression<Func<T, object>> GetMember<T>(string memberName)// where T : EntityObject
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
System.Reflection.PropertyInfo pi = typeof(T).GetProperty(memberName);
return (Expression<Func<T, object>>)Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(pe, pi), typeof(object)), pe);
}
but it produces : p =>Convert(p.PersonUID)
instead of:p =>p.PersonUID
Regards
GregJF
After a bit more testing (and a good night's sleep) I got the second method to work (Thanks to JA Rreyes )
My issue was that I was using this:
var groupByExpressionGN2 = GetGroupByExpressionGuidNull<DebtWaiver>("PersonUID");
...
// in the query
.GroupBy(groupByExpression2)
I should have being doing this:
var groupByExpression2 = GetMember<DebtWaiver>("PersonUID");
...
// in the query
.GroupBy(groupByExpression2.Compile())
You can use the second method in my original post( GetMember ), but I use this method('cos I like it!): Thanks: Taher Rahgooy
public static Expression<Func<T, object>> GetPropertySelector<T>(string propertyName)
{
var arg = Expression.Parameter(typeof(T), "gb");
var property = Expression.Property(arg, propertyName);
var conv = Expression.Convert(property, typeof(object));
var exp = Expression.Lambda<Func<T, object>>(conv, new ParameterExpression[] { arg });
return exp;
}
Regards
GregJF

sorting xtext AST through quickfix

I've Been Trying to change the order of nodes through quickfix, but something is wrong.
Here's my code in xtend:
#Fix(org.xtext.custom.conventions.validation.ConventionsValidator::CONVENTION_NOT_ORDERED)
def fixFeatureName( Issue issue, IssueResolutionAcceptor acceptor){
acceptor.accept(issue, 'Sort', "Sort '" + issue.data.head + "'", null)[
element, context |
var gr=(element as Greeting)
if (gr.name === null || gr.name.length === 0)
return;
var econt=gr.eContainer.eContents
var comparator = [ EObject obj1, EObject obj2 |
var o1 = (obj1 as Greeting)
var o2 = (obj2 as Greeting)
return o1.name.compareTo(o2.name)
]
ECollections::sort(econt, comparator)
]
}
No exception is being thrown to console, in debug I found an UnsupportedOperationException is thrown and handled by xtext.
I suspect that EList is immutable.
So how can I sort the AST?
(Here is the generated code: )
#Fix(ConventionsValidator.CONVENTION_NOT_ORDERED)
public void fixFeatureName(final Issue issue, final IssueResolutionAcceptor acceptor) {
String[] _data = issue.getData();
String _head = IterableExtensions.<String>head(((Iterable<String>)Conversions.doWrapArray(_data)));
String _plus = ("Sort \'" + _head);
String _plus_1 = (_plus + "\'");
final ISemanticModification _function = new ISemanticModification() {
public void apply(final EObject element, final IModificationContext context) throws Exception {
Greeting gr = ((Greeting) element);
boolean _or = false;
String _name = gr.getName();
boolean _tripleEquals = (_name == null);
if (_tripleEquals) {
_or = true;
} else {
String _name_1 = gr.getName();
int _length = _name_1.length();
boolean _tripleEquals_1 = (Integer.valueOf(_length) == Integer.valueOf(0));
_or = (_tripleEquals || _tripleEquals_1);
}
if (_or) {
return;
}
EObject _eContainer = gr.eContainer();
EList<EObject> econt = _eContainer.eContents();
final Function2<EObject,EObject,Integer> _function = new Function2<EObject,EObject,Integer>() {
public Integer apply(final EObject obj1, final EObject obj2) {
Greeting o1 = ((Greeting) obj1);
Greeting o2 = ((Greeting) obj2);
String _name = o1.getName();
String _name_1 = o2.getName();
return _name.compareTo(_name_1);
}
};
Function2<EObject,EObject,Integer> comparator = _function;
final Function2<EObject,EObject,Integer> _converted_comparator = (Function2<EObject,EObject,Integer>)comparator;
ECollections.<EObject>sort(econt, new Comparator<EObject>() {
public int compare(EObject o1,EObject o2) {
return _converted_comparator.apply(o1,o2);
}
});
}
};
acceptor.accept(issue, "Sort", _plus_1, null, _function);
}
thanks!
Sorting a temporary collection which will then replace econt didn't work. but I managed to solve it in a different way.
so one solution was to force a cast of eContainer as it's runtime element (which is Model), and then getting a list with it's getGreetings getter, and with that element the sorting works, but I didn't want to involve non-generic code, for technical reasons.
So after a lot of experiments I finally found that element without involving any other elements or keywords from the grammar:
var econt = (gr.eContainer.eGet(gr.eContainingFeature) as EObjectContainmentEList<Greeting>)
and that is exactly what was looking for. Sorting is successful!
Here's the resulting Xtend code (got rid of casing in the comperator as well):
#Fix(ConventionsValidator::CONVENTION_NOT_ORDERED)
def fixFeatureName(Issue issue, IssueResolutionAcceptor acceptor) {
acceptor.accept(issue, 'Sort', "Sort '" + issue.data.head + "'", null) [
element, context |
var gr = (element as Greeting)
if (gr.name === null || gr.name.length === 0)
return;
var econt = (gr.eContainer.eGet(gr.eContainingFeature) as EObjectContainmentEList<Greeting>)
var comparator = [ Greeting o1, Greeting o2 |
return o1.name.compareTo(o2.name)
]
ECollections::sort(econt, comparator)
]
}
and the generated java:
#Fix(ConventionsValidator.CONVENTION_NOT_ORDERED)
public void fixFeatureName(final Issue issue, final IssueResolutionAcceptor acceptor) {
String[] _data = issue.getData();
String _head = IterableExtensions.<String>head(((Iterable<String>)Conversions.doWrapArray(_data)));
String _plus = ("Sort \'" + _head);
String _plus_1 = (_plus + "\'");
final ISemanticModification _function = new ISemanticModification() {
public void apply(final EObject element, final IModificationContext context) throws Exception {
Greeting gr = ((Greeting) element);
boolean _or = false;
String _name = gr.getName();
boolean _tripleEquals = (_name == null);
if (_tripleEquals) {
_or = true;
} else {
String _name_1 = gr.getName();
int _length = _name_1.length();
boolean _tripleEquals_1 = (Integer.valueOf(_length) == Integer.valueOf(0));
_or = (_tripleEquals || _tripleEquals_1);
}
if (_or) {
return;
}
EObject _eContainer = gr.eContainer();
EStructuralFeature _eContainingFeature = gr.eContainingFeature();
Object _eGet = _eContainer.eGet(_eContainingFeature);
EObjectContainmentEList<Greeting> econt = ((EObjectContainmentEList<Greeting>) _eGet);
final Function2<Greeting,Greeting,Integer> _function = new Function2<Greeting,Greeting,Integer>() {
public Integer apply(final Greeting o1, final Greeting o2) {
String _name = o1.getName();
String _name_1 = o2.getName();
return _name.compareTo(_name_1);
}
};
Function2<Greeting,Greeting,Integer> comparator = _function;
final Function2<Greeting,Greeting,Integer> _converted_comparator = (Function2<Greeting,Greeting,Integer>)comparator;
ECollections.<Greeting>sort(econt, new Comparator<Greeting>() {
public int compare(Greeting o1,Greeting o2) {
return _converted_comparator.apply(o1,o2);
}
});
}
};
acceptor.accept(issue, "Sort", _plus_1, null, _function);
}

Need more efficient way to convert Entities to DataTable

So, I have a method that converts entities into a DataTable. The only problem is it is very slow. I made sure to call .ToList() on the IQueryable to make it go ahead and load before processing the results into a DataTable. It takes hardly any time to load the 3000+ rows into memory. However, the real time slayer is in the following iteration in the method:
foreach (var index in imgLeaseIndexes)
{
DataRow dataRow = dataTable.NewRow();
dataRow["StateCode"] = index.StateCode;
dataRow["CountyCode"] = index.CountyCode;
dataRow["EntryNumber"] = index.EntryNumber;
dataRow["Volume"] = index.Volume;
dataRow["Page"] = index.Page;
dataRow["PageCount"] = index.ImgLocation.PageCount;
dataRow["CreateDate"] = index.ImgLocation.CreateDate;
dataTable.Rows.Add(dataRow);
}
And here is the complete method, for what it's worth:
private DataTable buildImgLeaseIndexDataTable(List<ImgLeaseIndex> imgLeaseIndexes)
{
var dataTable = new DataTable();
var dataColumns = new List<DataColumn>();
var tdiReportProperties =
new List<string>() { "StateCode", "CountyCode", "EntryNumber", "Volume", "Page", "PageCount", "CreateDate" };
Type imgLeaseIndexType = imgLeaseIndexes.FirstOrDefault().GetType();
PropertyInfo[] imgLeaseIndexPropertyInfo = imgLeaseIndexType.GetProperties();
dataColumns.AddRange(
(from propertyInfo in imgLeaseIndexPropertyInfo
where tdiReportProperties.Contains(propertyInfo.Name)
select new DataColumn()
{
ColumnName = propertyInfo.Name,
DataType = (propertyInfo.PropertyType.IsGenericType &&
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) ?
propertyInfo.PropertyType.GetGenericArguments()[0] : propertyInfo.PropertyType
})
.ToList());
Type imgLocationType = imgLeaseIndexes.FirstOrDefault().ImgLocation.GetType();
PropertyInfo[] imgLocationPropertyInfo = imgLocationType.GetProperties();
dataColumns.AddRange(
(from propertyInfo in imgLocationPropertyInfo
where tdiReportProperties.Contains(propertyInfo.Name)
select new DataColumn()
{
ColumnName = propertyInfo.Name,
DataType = (propertyInfo.PropertyType.IsGenericType &&
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) ?
propertyInfo.PropertyType.GetGenericArguments()[0] : propertyInfo.PropertyType
})
.ToList());
dataTable.Columns.AddRange(dataColumns.ToArray());
foreach (var index in imgLeaseIndexes)
{
DataRow dataRow = dataTable.NewRow();
dataRow["StateCode"] = index.StateCode;
dataRow["CountyCode"] = index.CountyCode;
dataRow["EntryNumber"] = index.EntryNumber;
dataRow["Volume"] = index.Volume;
dataRow["Page"] = index.Page;
dataRow["PageCount"] = index.ImgLocation.PageCount;
dataRow["CreateDate"] = index.ImgLocation.CreateDate;
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
Does anyone have ideas on how I can make this more efficient and why it is so slow as is?
UPDATE:
I removed the reflection and explicitly set the data columns at compile time per the feedback I've received so far, but it is still really slow. This is what the updated code looks like:
private DataTable buildImgLeaseIndexDataTable(List<ImgLeaseIndex> imgLeaseIndexes)
{
var dataTable = new DataTable();
var stateCodeDataColumn = new DataColumn();
stateCodeDataColumn.ColumnName = "StateCode";
stateCodeDataColumn.Caption = "State Code";
stateCodeDataColumn.DataType = typeof(Int16);
dataTable.Columns.Add(stateCodeDataColumn);
var countyCodeDataColumn = new DataColumn();
countyCodeDataColumn.ColumnName = "CountyCode";
countyCodeDataColumn.Caption = "County Code";
countyCodeDataColumn.DataType = typeof(Int16);
dataTable.Columns.Add(countyCodeDataColumn);
var entryNumberDataColumn = new DataColumn();
entryNumberDataColumn.ColumnName = "EntryNumber";
entryNumberDataColumn.Caption = "Entry Number";
entryNumberDataColumn.DataType = typeof(string);
dataTable.Columns.Add(entryNumberDataColumn);
var volumeDataColumn = new DataColumn();
volumeDataColumn.ColumnName = "Volume";
volumeDataColumn.DataType = typeof(string);
dataTable.Columns.Add(volumeDataColumn);
var pageDataColumn = new DataColumn();
pageDataColumn.ColumnName = "Page";
pageDataColumn.DataType = typeof(string);
dataTable.Columns.Add(pageDataColumn);
var pageCountDataColumn = new DataColumn();
pageCountDataColumn.ColumnName = "PageCount";
pageCountDataColumn.Caption = "Page Count";
pageCountDataColumn.DataType = typeof(string);
dataTable.Columns.Add(pageCountDataColumn);
var createDateDataColumn = new DataColumn();
createDateDataColumn.ColumnName = "CreateDate";
createDateDataColumn.Caption = "Create Date";
createDateDataColumn.DataType = typeof(DateTime);
dataTable.Columns.Add(createDateDataColumn);
foreach (var index in imgLeaseIndexes)
{
DataRow dataRow = dataTable.NewRow();
dataRow["StateCode"] = index.StateCode;
dataRow["CountyCode"] = index.CountyCode;
dataRow["EntryNumber"] = index.EntryNumber;
dataRow["Volume"] = index.Volume;
dataRow["Page"] = index.Page;
dataRow["PageCount"] = index.ImgLocation.PageCount;
dataRow["CreateDate"] = index.ImgLocation.CreateDate;
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
Any ideas on what else might be causing this?
UPDATE 2:
So it looks like other people have had this problem - specific to creating and setting the DataRows. My co-worker came across this:
The DataRow value setter is slow!
I'm going to try some of the stuff suggested in the link.
As Thiago mentioned in the comments the problem is the use of reflection.
The reflection part is where you are using PropertyInfo. You are getting the structure of the data types at runtime. But these are known at compile time.