Linq query to get all pending Loans - c#

I have two tables in lightswitch LOANS(Id(default),..) and RELEASES(Id(default),Loan,..).i want to create a screen with all pending loans to be shown in a datagrid.so i created a wcf RIA class library.i wanto return all the loans that have no releases yet.what would be the linq query for that.
i tried this from other SO post but it gave a null reference exception.Nullreference exception was unhandled by user code.Object reference not set to an instance of object
Loan to Release has 1 : 0/1 (one loan to zero or one release)relationship
a loan can have zero or one relationship.a release must have a loan.
[Query(IsDefault = true)]
public IQueryable<PendingLoans> GetPendingLoans()
{
var res = from l in this.context.Loans
join r in this.context.Releases
on l equals r.Loan
where r.Loan == null
select new PendingLoans { BillNo = l.BillNo };
return res.AsQueryable<PendingLoans>();
}

Try this, this is linq but using lambdas instead of the query syntax
[Query(IsDefault = true)]
public IQueryable<PendingLoans> GetPendingLoans()
{
var res = this.context.Loans.Where(l=>!l.Releases.Any()).Select(l=> new PendingLoans { BillNo = l.BillNo }).AsQueryable();
return res;
}
If you want to use the query syntax this is effectively the same thing
[Query(IsDefault = true)]
public IQueryable<PendingLoans> GetPendingLoans()
{
var res = from l in this.context.Loans
where !l.Releases.Any()
select new PendingLoans { BillNo = l.BillNo };
return res.AsQueryable();
}
Now one thing I will say is that because you're converting to a PendingLoan before you say "AsQueryable", you've already enumerated over your data set (converting from one type of object to another). Therefore this will not have the same benefits of late bindings you may be trying to get out of the "AsQueryable" portion (You've already executed against the db), so you may be better off just returning an IEnumerable and forgetting about the AsQueryable part since you've already enumerated once.

Related

Linq Query not giving the expected result

After a quite complicated rework of code I stumbled over a small part of code which is not giving me the expected result. The following Linq query should query the data contained in the main object by selecting only those containing a particular string.
The main list contains about 5500 entries. after execution of the Linq query, the secondary object contains still these 5500 entries. Am I blind or already mentally deranged? The CompanyName parameter contains a company which effectively exists.
UPDATE: If the data is taken from the cache the list contains all relevant entries, just the query seems to have no effect.
public List<Account> GetAccountsByValue(string CompanyName)
{
string CacheKey = "Accounts";
ObjectCache dataCache = MemoryCache.Default;
if (dataCache.Contains(CacheKey))
{
var ResultCached = (IEnumerable<Account>)dataCache.Get(CacheKey);
var ResultCached2 = from c in ResultCached
where c.Name.Contains(CompanyName)
select new
{
c.Name,
c.Street,
c.City,
c.ID
};
var temp = ResultCached2.ToList();
return temp;
}
else
{
IList<CrmAccount> Accounts = CrmServiceAgent.GetAccounts();
var ResultNoCache = from CrmAccount f in Accounts
orderby f.DisplayName
select new Account(f);
// put the data in the cache
CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
cacheItemPolicy.AbsoluteExpiration = DateTime.Now.AddHours(4.0);
dataCache.Add(CacheKey, ResultNoCache, cacheItemPolicy);
return ResultNoCache.ToList();
}
}
The List of data which is queried looks like this (in WCF Test Client)
Everything works fine, just only the query part is not having effect which means that again all entries are returned instead of only thos containing the query parameter.
UPDATE:
Actually I get an Null Reference Exception, probably because the Name-Attribute of the first few entries is null....
This is throwing now the error:
var ResultCached3 = ResultCached.Where(c => c.Name.Contains(CompanyName)).ToList();
I have now fixed the whole thing. The data queried from the database now does not contain any null values anymore. The problem was, that mandatory fields where checked only in the frontend and not on database level. so data which usually is mandatory was imported as null values
so now in the List I have only "valid" data and now the linq query works as it should.
Thank you all for your hints ans suggestions!
kind regards
Sandro
var ResultCached2 = (from c in ResultCached
where c.Name.Contains(CompanyName)
select new
{
c.Name,
c.Street,
c.City,
c.ID
}).ToList();

How to create a custom property in a Linq-to-SQL entity class?

I have two tables Studies and Series. Series are FK'd back to Studies so one Study contains a variable number of Series.
Each Series item has a Deleted column indicating it has been logically deleted from the database.
I am trying to implement a Deleted property in the Study class that returns true only if all the contained Series are deleted.
I am using O/R Designer generated classes, so I added the following to the user modifiable partial class for the Study type:
public bool Deleted
{
get
{
var nonDeletedSeries = from s in Series
where !s.Deleted
select s;
return nonDeletedSeries.Count() == 0;
}
set
{
foreach (var series in Series)
{
series.Deleted = value;
}
}
}
This gives an exception "The member 'PiccoloDatabase.Study.Deleted' has no supported translation to SQL." when this simple query is executed that invokes get:
IQueryable<Study> dataQuery = dbCtxt.Studies;
dataQuery = dataQuery.Where((s) => !s.Deleted);
foreach (var study in dataQuery)
{
...
}
Based on this http://www.foliotek.com/devblog/using-custom-properties-inside-linq-to-sql-queries/, I tried the following approach:
static Expression<Func<Study, bool>> DeletedExpr = t => false;
public bool Deleted
{
get
{
var nameFunc = DeletedExpr.Compile();
return nameFunc(this);
}
set
{ ... same as before
}
}
I get the same exception when a query is run that there is no supported translation to SQL. (
The logic of the lambda expression is irrelevant yet - just trying to get past the exception.)
Am I missing some fundamental property or something to allow translation to SQL? I've read most of the posts on SO about this exception, but nothing seems to fit my case exactly.
I believe the point of LINQ-to-SQL is that your entities are mapped for you and must have correlations in the database. It appears that you are trying to mix the LINQ-to-Objects and LINQ-to-SQL.
If the Series table has a Deleted field in the database, and the Study table does not but you would like to translate logical Study.Deleted into SQL, then extension would be a way to go.
public static class StudyExtensions
{
public static IQueryable<study> AllDeleted(this IQueryable<study> studies)
{
return studies.Where(study => !study.series.Any(series => !series.deleted));
}
}
class Program
{
public static void Main()
{
DBDataContext db = new DBDataContext();
db.Log = Console.Out;
var deletedStudies =
from study in db.studies.AllDeleted()
select study;
foreach (var study in deletedStudies)
{
Console.WriteLine(study.name);
}
}
}
This maps your "deleted study" expression into SQL:
SELECT t0.study_id, t0.name
FROM study AS t0
WHERE NOT EXISTS(
SELECT NULL AS EMPTY
FROM series AS t1
WHERE (NOT (t1.deleted = 1)) AND (t1.fk_study_id = t0.study_id)
)
Alternatively you could build actual expressions and inject them into your query, but that is an overkill.
If however, neither Series nor Study has the Deleted field in the database, but only in memory, then you need to first convert your query to IEnumerable and only then access the Deleted property. However doing so would transfer records into memory before applying the predicate and could potentially be expensive. I.e.
var deletedStudies =
from study in db.studies.ToList()
where study.Deleted
select study;
foreach (var study in deletedStudies)
{
Console.WriteLine(study.name);
}
When you make your query, you will want to use the statically defined Expression, not the property.
Effectively, instead of:
dataQuery = dataQuery.Where((s) => !s.Deleted);
Whenever you are making a Linq to SQL query, you will instead want to use:
dataQuery = dataQuery.Where(DeletedExpr);
Note that this will require that you can see DeletedExpr from dataQuery, so you will either need to move it out of your class, or expose it (i.e. make it public, in which case you would access it via the class definition: Series.DeletedExpr).
Also, an Expression is limited in that it cannot have a function body. So, DeletedExpr might look something like:
public static Expression<Func<Study, bool>> DeletedExpr = s => s.Series.Any(se => se.Deleted);
The property is added simply for convenience, so that you can also use it as a part of your code objects without needing to duplicate the code, i.e.
var s = new Study();
if (s.Deleted)
...

How do I create a list object that contains a list of another object type using from within a query using linq and c#

I am trying to return a list of an object that contains another object list as a databmember using linq. I've tried the examples shown but I keep getting ad different error with each attempt. One of which is as follows: LINQ to Entities does not recognize the method 'System.Collections.Generic.List1[SunGard.Tools.Notifications.LinkVariable] ToList[LinkVariable](System.Collections.Generic.IEnumerable1[SunGard.Tools.Notifications.LinkVariable])' method, and this method cannot be translated into a store expression.
I have an object (AlertMessageReturn) that contains some string datamembers as well as a list aof another object (List). I have a class that defines the LinkVarible and a table that contains the values. My query looks like this:
AlertMessagesQuery = from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new AlertMessageReturn()
{ PAM_ShortMessage = alertMessage.PAM_ShortMessage,
PAM_LongMessage = alertMessage.PAM_LongMessage,
PAM_LongMessageRemote = alertMessage.PAM_LongMessageRemote,
LinkVariables = (from linkVariable in this.context.AlertMessageLinks
from user in this.context.AlertMessageUsers
where user.PAMU_PAM_ID == linkVariable.PAML_PAM_ID && user.PAMU_UserId == UserId
select new LinkVariable()
{
Name = linkVariable.PAML_SessionVariableName,
Value = linkVariable.PAML_SessionVariableValue
})
};
The error is related to the type returned for linkvariables.
Please help.
I changed the code as follows:
LinkDataQuery = from linkData in this.context.AlertMessageLinks
from user1 in this.context.AlertMessageUsers
where user1.PAMU_PAM_ID == linkData.PAML_PAM_ID && user1.PAMU_UserId == UserId
select new LinkData
{
Name = linkData.PAML_SessionVariableName,
Value = linkData.PAML_SessionVariableValue
};
var links = LinkDataQuery.ToList();
AlertMessagesQuery = from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new AlertMessageReturn()
{ PAM_ShortMessage = alertMessage.PAM_ShortMessage,
PAM_LongMessage = alertMessage.PAM_LongMessage,
PAM_LongMessageRemote = alertMessage.PAM_LongMessageRemote,
LinkVariables = links
};
var AlertMessages = AlertMessagesQuery.ToList(); // this is where the error point to
if (AlertMessages.Any())
{
return AlertMessages;
}
The error I now get is:System.NotSupportedException: Unable to create a constant value of type 'SunGard.Tools.Notifications.LinkData'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
The LINQ to SQL engine cannot turn your sub-query to generate the LinkVariables into SQL. More importantly, SQL cannot return nested data sets like that.
Any time you get a message of type 'cannot be translated into a store expression' it is an indicator that you are doing something with your linq that is attempting to be translated into other statements (usually SQL). For example, if you say
....select new MyObject
{
Id = Guid.Parse( passedIdentity ),
....
}
while this is a totally valid C# statement you will get an error that Guid.Parse cannot be handled by linq. If it is possible to move the variables into external variables that are used inside the query then it would work. So you would do...
string name = linkVariable.PAML_SessionVariableName;
string nValue = ....
....
select New LinkVariable
{
Name=name,
Value=nValue
};
Also ... you do not need the closing parens on the Select New statement.
While LINQ to SQL can bring back object heirarchies, it can't project into types that aren't part of the model. Instead of projecting into the AlertMessageReturn type, try projecting into an anonymous type in the IQueryable portion of the code. Once you're done structuring your database query, force the results to come back (using AsEnumerable) and then project that into your AlertMessageReturn type. It's more overhead, but does work. Alternatively, you can use something like AutoMapper to translate your anonymous type into the result types.
AlertMessagesQuery =
from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new
{
alertMessage.PAM_ShortMessage,
alertMessage.PAM_LongMessage,
alertMessage.PAM_LongMessageRemote,
LinkVariables = from linkVariable in this.context.AlertMessageLinks
from user in this.context.AlertMessageUsers
where user.PAMU_PAM_ID == linkVariable.PAML_PAM_ID && user.PAMU_UserId == UserId
select new
{
Name = linkVariable.PAML_SessionVariableName,
Value = linkVariable.PAML_SessionVariableValue
})
};
var alertMessageResults =
from message in AlertMessagesQuery.AsEnumerable()
select new AlertMessageResult
{
PAM_ShortMessage = mesage.PAM_ShortMessage,
PAM_LongMessage = message.PAM_LongMessage,
PAM_LongMessageRemote = message.PAM_LongMessageRemote,
LinkVariables = (from variable in message.LinkVariables
select new LinkVariable { Name=variable.Name, Value = variable.Value})
.ToList()
};
return alertMessageResults.ToList();

ASP.NET MVC 3 / Razor - Strange Caching Issue

I'm using a LinqToSql query to select a list of groups from a database and spew out a table. I've written a custom class to cache the results of this query for better performance. Trouble is, whenever I implement the caching class, I get weird appending behaviour from the outputting statement.
My results are outputted in the format
Test Group (1)
where "Test Group" is the name, and (1) is the number of members within that group. Here's the code that appends the count to the name (from the view)
<td>#group.group_name (#group.num_total)</td>
When I pull this from a live linq query returning groups, everything works as expected.
However, when I use my caching class, every successive page load adds the number on to the end of the group title:
Test Group (1) (1) (1) (1) (1) (1)
This only happens when I use the caching class (included below). I've been over the cache class and there's no reason I can see why this would be happening.
I can think of several workarounds for this issue, so its not a show stopper, but I'm curious as to what the fudge is going on. Any ideas?
Caching Class:
public class Cache
{
public static int user_id {
get { return
Convert.ToInt32(
Membership.GetUser(
HttpContext.Current.User.Identity.Name
).ProviderUserKey
);
}
}
public static void GetGroups_InvalidateCache()
{
if (HttpContext.Current.Cache["GetGroups_" + user_id] != null)
HttpContext.Current.Cache.Remove("GetGroups_" + user_id);
}
public static ICollection<Groups> GetGroups()
{
if (HttpContext.Current.Cache["GetGroups_" + user_id] == null)
{
using(DBContext db = new DBContext())
{
var Groups = (from g in db.Groups
where g.user_id == user_id
select g).ToList();
HttpContext.Current.Cache.Insert(
"GetGroups_" + user_id,
Groups,
null,
DateTime.Now.AddMinutes(5),
TimeSpan.Zero
);
}
}
return HttpContext.Current.Cache["GetGroups_" + user_id]
as ICollection<Groups>;
}
}
UPDATE:
I've now implemented Adam Tuliper and Paul Tyng's suggestions of calling the data context with the using clause, ending the linq statement with ToList() and using ICollection instead of IQueryable. The problem is still occurring.
Another interesting observation: The issue only happens if I navigate away to another page and return. If I simply refresh the page, it doesn't happen (Although any previous number additions still remain when I refresh)
Instead of returning IQueryable, try using simply IEnumerable and also using
using(DBContext db = new DBContext())
{
var Groups =
(from g in db.Groups
where g.user_id == user_id
select g).ToList();
...
}
Also dispose of your context as in the above statement (with the using clause)
The ToList() forces the execution "now" - I think you are potentially having deferred execution issues

How to return query results from method that uses LINQ to SQL

Here is the code I'm working with, I'm still a bit new to LINQ, so this is a work in progress. Specifically, I'd like to get my results from this query (about 7 columns of strings, ints, and datetime), and return them to the method that called the method containing this LINQ to SQL query. A simple code example would be super helpful.
using (ormDataContext context = new ormDataContext(connStr))
{
var electionInfo = from t1 in context.elections
join t2 in context.election_status
on t1.statusID equals t2.statusID
select new { t1, t2 };
}
(In this case, my query is returning all the contents of 2 tables, election and election_status.)
Specifically, I'd like to get my
results from this query (about 7
columns of strings, ints, and
datetime), and return them
Hi, the problem you've got with your query is that you're creating an anonymous type. You cannot return an anonymous type from a method, so this is where you're going to have trouble.
What you will need to do is to create a "wrapper" type that can take an election and an election_status and then return those.
Here's a little sample of what I'm talking about; as you can see I declare a Tuple class. The method that you will wrap your query in returns an IEnumerable.
I hope this helps :-)
class Tuple
{
Election election;
Election_status election_status;
public Tuple(Election election, Election_status election_status)
{
this.election = election;
this.election_status = election_status;
}
}
public IEnumerable<Tuple> getElections()
{
IEnumerable<Tuple> result = null;
using (ormDataContext context = new ormDataContext(connStr))
{
result = from t1 in context.elections
join t2 in context.election_status
on t1.statusID equals t2.statusID
select new Tuple(t1, t2);
}
}
UPDATE
Following from NagaMensch's comments, a better way to achieve the desired result would be to use the built in LINQ to SQL associations.
If you go to your entity diagram and click on toolbox, you will see 3 options. Class, Association and Inheritance. We want to use Association.
Click on Association and click on the ElectionStatus entity, hold the mouse button down and it will allow you to draw a line to the Election entity.
Once you've drawn the line it will ask you which properties are involved in the association. You want to select the StatusId column from the Election entity, and the StatusId column from the ElectionStatus entity.
Now that you've completed your mapping you will be able to simplify your query greatly because the join will not be necessary. You can just access the election status via a brand new property that LINQ to SQL will have added to the Election entity.
Your code can now look like this:
//context has to be moved outside the function
static ExampleDataContext context = new ExampleDataContext();
//Here we can return an IEnumerable of Election now, instead of using the Tuple class
public static IEnumerable<Election> getElections()
{
return from election in context.Elections
select election;
}
static void Main(string[] args)
{
//get the elections
var elections = getElections();
//lets go through the elections
foreach (var election in elections)
{
//here we can access election status via the ElectionStatus property
Console.WriteLine("Election name: {0}; Election status: {1}", election.ElectionName, election.ElectionStatus.StatusDescription);
}
}
You can also find a "how to" on LINQ to SQL associations here.
Note: It's worth mentioning that if you have an FK relationship set up between your tables in the database; LINQ to SQL will automatically pick the relationship up and map the association for you (therefore creating the properties).
You'll need to create classes that have the same structure as the anonymous types. Then, instead of "new { t1, t2 }", you use "new MyClass(t1, t2)".
Once you have a named class, you can pass it all over the place as you were hoping.
The problem is, that you are creating a anonymous type, hence there is no way to declare a method with this return type. You have to create a new type that will hold your query result and return this type.
But I suggest not to return the result in a new type but return just a colection of election objects and access the election_status objects through the relation properties assuming you included them in your model. The data load options cause the query to include the related election status objects in the query result.
public IList<election> GetElections()
{
using (ormDataContext context = new ormDataContext(connStr))
{
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<election>(e => e.election_status);
context.DeferredLoadingEnabled = false;
context.LoadOptions = dlo;
return context.elections.ToList();
}
}
Now you can do the following.
IList<election> elections = GetElections();
// Access the election status.
Console.WriteLin(elections[0].election_status);
I general LINQ to SQL could just retrieve the related entities on demand - that is called deferred loading.
ormDataContext context = new ormDataContext(connStr));
IList<election> elections = context.elections.ToList();
// This will trigger a query that loads the election
// status of the first election object.
Console.WriteLine(elections[0].election_status);
But this requires you not to close the data context until you finished using the retrieved objects, hence cannot be used with a using statement encapsulated in a method.
IEnumerable<object> getRecordsList()
{
using (var dbObj = new OrderEntryDbEntities())
{
return (from orderRec in dbObj.structSTIOrderUpdateTbls
select orderRec).ToList<object>();
}
}
maybe it can help :)
using (ormDataContext context = new ormDataContext(connStr))
{
var electionInfo = from t1 in context.elections
join t2 in context.election_status
on t1.statusID equals t2.statusID
select new {
t1.column1,
t1.column2,
t1.column3,
t1.column4,
t2.column5,
t2.column6,
t2.column7
};
}
foreach (var ei in electionInfo){
//write what do u want
}
return electionInfo.ToList();
You cannot return an anonymous type from a method. It is only available within the scope in which it is created. You'll have to create a class instead.

Categories

Resources