dynamically add IEnumerable<int?> on group by result set in c# - c#

Can any suggest me to figure out this requirement.
var enableIds = context.items.Where(tble => tble.Date == null)
.GroupBy(a => a.Id)
.Select(g => new
{
Id = g.Key,
EId = g.Select(c => c.EId).Distinct()
});
For above query i'm getting below result set
"Id\":1,\"EId\":[1,2]
Now i've to add -1 value to EId dynamically like this ("EId\":[1,2,-1] )

You could use an Enumerable Concat extension:
var enableIds = context.items.Where(tble => tble.Date == null)
.GroupBy(a => a.Id)
.Select(g => new
{
Id = g.Key,
EId = g.Select(c => c.EId).Distinct()).ToList().Concat(new[] { -1 })
});

I would try something like this using a helper method Concat<T>. The helper method could be implemented as an extension method for the IEnumerable<T>.
var enableIds = _db.items.Where(tble => tble.Date == null)
.GroupBy(a => a.Id)
.Select(g => new
{
Id = g.Key,
EId = Concat(g.Select(c => c.EId).Distinct(), -1)
});
public static IEnumerable<T> Concat<T>(IEnumerable<T> enumerable, params T[] enumerable2)
{
if (enumerable == null) throw new ArgumentNullException("enumerable");
if (enumerable2 == null) throw new ArgumentNullException("enumerable2");
foreach (T t in enumerable)
{
yield return t;
}
foreach (T t in enumerable2)
{
yield return t;
}
}

Related

How to increase SQL parser speed that using TSqlParser?

In my code, I have several SQL scripts that I want to parse using TSql130Parser in order to refactor them. But this process takes a long time - is there a way to increase the speed of this?
Also I have another question that TSql130Parser can get bulk as parameter? If it is possible, how can I do it?
This is my method that I use for parsing procedures by passing content of procedure as query in method parameter:
public string ParseProcedureQuery(string query, out string procedureName)
{
procedureName= "";
try
{
TSql130Parser parser = new TSql130Parser(true);
IList<ParseError> errors;
var fragments = parser.Parse(new System.IO.StringReader(query), out errors);
var proc = fragments.ScriptTokenStream.Where(x => x.TokenType == TSqlTokenType.Proc || x.TokenType == TSqlTokenType.Procedure).Select(x => x.Text).FirstOrDefault();
if (proc == null)
return string.Empty;
var index = fragments.ScriptTokenStream.FindIndex(c => c.Text == proc);
var name = fragments.ScriptTokenStream
.Select((value, ind) => new { value, index = ind })
.Where(pair => pair.index > index && pair.value.TokenType != TSqlTokenType.WhiteSpace)
.Select((value, ind) => new { value.value.Text, index = ind }).Where(y => y.index < 3).Select(p => p.Text);
procedureName = string.Join(String.Empty, name);
var processedQuery = string.Join(" ", fragments.ScriptTokenStream
.Where(x => x.TokenType != TSqlTokenType.MultilineComment)
.Where(x => x.TokenType != TSqlTokenType.SingleLineComment)
.Where(x => x.TokenType != TSqlTokenType.WhiteSpace)
.Select(x => x.Text));
return processedQuery;
}
catch
{ }
}

Summing a decimal field using Linq to datatable

I was able to get this to work after much frustration, but I was hoping someone could explain to me why this works:
var monthCharges = WRVUData.AsEnumerable()
.Where(dr => dr.Field<DateTime>("Posting_Month") == new DateTime(month.Year, i, 1))
.Where(dr => dr.Field<string>("Report_Producer_Name") == provider || dr.Field<string>("Group_Name") == group)
.Where(dr => dr.Field<decimal?>("Charges") != null)
.Sum(dr => dr.Field<decimal>("Charges"));
but this doesn't:
var monthCharges = (from r in WRVUData.AsDataView()
select new
{
charges = r.Field<decimal?>("Charges"),
activityType = r.Field<string>("Activity_Type"),
postingMonth = r.Field<DateTime>("Posting_Month"),
provider = r.Field<string>("Report_Producer_Name"),
groupName = r.Field<string>("Group_Name"),
WRVUs = r.Field<decimal>("W_RVUs")
})
.Where(dr => dr.postingMonth == new DateTime(month.Year, i, 1))
.Where(dr => dr.provider == provider || dr.groupName == group)
.Where(dr => dr.charges != null)
.Sum(dr => dr.charges);
The second version throws a "Specified cast is not valid" error. Aren't the two basically the same thing?

LINQ GroupBy List<>

I have a straightforward LINQ query that is attempting to perform a GroupBy where one of the items in the statements is a List<string>.
var viewModel = reports
.GroupBy(c => new { c.Id, c.PetList })
.Select(g => new ArmReportModel
{
PetList = g.Key.PetList,
Pets = g.Count()
});
Prior to this statement I am executing my EF repository method which ultimately calls a method to create the PetList above.
If I remove the PetList from the GroupBy() it works as expected. Is there something I must do in order to group by a List<string> type?
I would assume that Id is an identifier, and hence any two c with the same Id is in fact the same and has the same PetList. As such we can GroupBy just the Id and get the PetList another way:
var viewModel = reports
.GroupBy(c => c.Id)
.Select(g => new ArmReportModel
{
PetList = g.First().PetList, // Might need FirstOrDefault() with some providers
Pets = g.Count()
});
Barring that, I'd want to first make sure I could use an IEqualityComparer<T> with the GroupBy. If the provider allows for that, then no problem. Otherwise I'd start with:
reports.Select(c => new {c.Id, c.PetList}).AsEnumerable()
This retrieves the minimum necessary from the provider into memory, so that the linq-to-objects provider can be used from that point on.
I need to be able to define an IEqualityComparer<T> for some T, so I stop using anonymous types:
private class IdAndList
{
public int Id { get; set; }
public List<string> PetList { get; set; }
}
private class ReportIdAndPetListComparer : IEqualityComparer<IdAndList>
{
public bool Equals(IdAndList x, IdAndList y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
if (x.Id != y.Id) return false;
if (x.PetList == null) return y.PetList == null;
if (y.PetList == null) return false;
int count = x.PetList.Count;
if (y.PetList.Count != count) return false;
for (int i = 0; i != count; ++i)
if (x.PetList[i] != y.PetList[i]) return false;
return true;
}
public int GetHashCode(IdAndList obj)
{
int hash = obj.Id;
if (obj.PetList != null)
foreach (string pet in obj.PetList)
hash = hash * 31 + pet.GetHashCode();
return hash;
}
}
Some of the tests for null PetLists can be removed if you know that's not possible.
Now:
var viewModel = reports.Select(c => new IdAndList{c.Id, c.PetList}).AsEnumerable()
.GroupBy(c => c, new ReportIdAndPetListComparer())
.Select(g => new ArmReportModel
{
PetList = g.Key.PetList,
Pets = g.Count()
});
Or if the provider can't deal with constructing the IdAndPetList type, then:
var viewModel = reports.Select(c => new {c.Id, c.PetList})
.AsEnumerable()
.Select(c => new IdAndList{c.Id, c.PetList})
.GroupBy(c => c, new ReportIdAndPetListComparer())
.Select(g => new ArmReportModel
{
PetList = g.Key.PetList,
Pets = g.Count()
});

Creating an anonymous type depending on different conditions and casting it to a class

I have this problem for sometime now but today I reached the tipping point and I'm asking for your help.
Suppose I have this code:
var query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
// Do the work
}
I end up with this anonymous type and everything is fine. Now something comes up that makes me condition the Where clause, so I have to make a different query according to the condition and this is where I'm really frustrated:
if(something)
{
var query = DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
// Do the work
}
}
else
{
var query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
// Do the work
}
}
because the work to be done in the foreach cycle is exactly the same and I shouldn't have to repeat it.
So, instead of working with the anonymous type I declared a new class and tried this:
class MyQuery
{
public int a { get; set; }
public string b { get; set; }
public decimal? c { get; set; }
}
IQueryable<MyQuery> query = null;
if(something)
{
query = (IQueryable<MyQuery>)DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c });
}
else
{
query = (IQueryable<MyQuery>)DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
}
foreach(var item in query)
{
// Do the work
}
But now I have an 'System.InvalidCastException' thrown because I'm still getting an anonymous type and apparently it can't be casted into my class.
I want to avoid the repetition of code for the sake of maintenance but I don't know how to do it. I feel that I'm missing something basic here but can't find what so your help is welcome and appreciated.
Thanks a lot for your help.
You are overcomplicating it:
IQueryable<MyQuery> query = DbContext.Table;
if (something)
{
query = query.Where(x => x.z == true && x.zz == false)
}
else
{
query = query.Where(x => x.z == true);
}
var result = query.Select(x => new { x.a, x.b, x.c });
foreach (var item in result)
{
// Do the work
}
The .Where() method doesn't change the "type" of the query!
Note even that this is legal:
var query = DbContext.Table.Select(x => new { x.a, x.b, x.c });
if (something)
{
query = DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c });
}
else
{
query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
}
foreach (var item in query)
{
// Do the work
}
I'm using the fact that anonymous types with the same parameters (same name of the parameters, same type of parameters, same number of parameters) inside the same assembly are "unified" by the C# compiler. I use this line var query = DbContext.Table.Select(x => new { x.a, x.b, x.c }); only to "give" the type to the var variable. Then I overwrite completely the query with other queries, because the various .Select(x => new { x.a, x.b, x.c }); "produce" objects of the same (anonymous) type.
You can modify the Where condition to match a case or another. This way you no longer need to worry about duplicate code or creating another class that will be used only on this method.
var query = DbContext.Table.Where(x => something && (x.z == true && x.zz == false) || !something && (x.z == true)).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
// Do the work
}
Or you can add a ternary comparison how #Rawling mentioned.
var query = DbContext.Table.Where(x => something ? (x.z == true && x.zz == false) : (x.z == true)).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
// Do the work
}

Convert string to guid in linq join query : conditional statement

I have linq query as below
using (RMPortalEntities _RMPortalEntities = new RMPortalEntities()) {
var _RSVP_ButtonLocations = _RMPortalEntities
.tbl_RSVP_ButtonLocation
.Join(_RMPortalEntities.tbl_RSVP_Setting,
_RSVP_ButtonLocation => Guid.Parse(_RSVP_ButtonLocation.ID),
_RSVP_Setting => _RSVP_Setting.RSVP_Button_Location_ID,
(_RSVP_ButtonLocation, _RSVP_Setting) => new { _RSVP_ButtonLocation, _RSVP_Setting })
.Join(_RMPortalEntities.tbl_Event,
_RSVP_ButtonLocation_RSVP_Setting => _RSVP_ButtonLocation_RSVP_Setting._RSVP_Setting.EventID,
_Event => _Event.ID,
(_RSVP_ButtonLocation_RSVP_Setting, _Event) => new { _RSVP_ButtonLocation_RSVP_Setting, _Event })
.Where(x => x._Event.Active == true
&& x._Event.ID == _EventID)
.Select(x => new
{
RSVP_ButtonLocations = x._RSVP_ButtonLocation_RSVP_Setting._RSVP_ButtonLocation.RSVP_ButtonLocation
});
return _RSVP_ButtonLocations.FirstOrDefault().RSVP_ButtonLocations;
}
But problem is linq query does not allow me to convert string to Guid value.
Could anyone give me suggestion please?
Building on CjCoax comment you can store an instance of GUID and then use it later in the query:
using (RMPortalEntities _RMPortalEntities = new RMPortalEntities()) {
var GUID = new Guid(_RMPortalEntities.tbl_RSVP_ButtonLocation.ID);
var _RSVP_ButtonLocations = _RMPortalEntities
.tbl_RSVP_ButtonLocation
.Join(_RMPortalEntities.tbl_RSVP_Setting,
_RSVP_ButtonLocation => GUID,
_RSVP_Setting => _RSVP_Setting.RSVP_Button_Location_ID,
(_RSVP_ButtonLocation, _RSVP_Setting) => new { _RSVP_ButtonLocation, _RSVP_Setting })
.Join(_RMPortalEntities.tbl_Event,
_RSVP_ButtonLocation_RSVP_Setting => _RSVP_ButtonLocation_RSVP_Setting._RSVP_Setting.EventID,
_Event => _Event.ID,
(_RSVP_ButtonLocation_RSVP_Setting, _Event) => new { _RSVP_ButtonLocation_RSVP_Setting, _Event })
.Where(x => x._Event.Active == true
&& x._Event.ID == _EventID)
.Select(x => new
{
RSVP_ButtonLocations = x._RSVP_ButtonLocation_RSVP_Setting._RSVP_ButtonLocation.RSVP_ButtonLocation
});
return _RSVP_ButtonLocations.FirstOrDefault().RSVP_ButtonLocations;
}

Categories