Hey i am making a simple search machine through alot of different coloumns in 2 tables.
I was trying to get this to abit dynamical.
I read this:
Is there a pattern using Linq to dynamically create a filter?
Which is something that really could do the trick for me.. its just in VB and i need it in c#
here is my code :
private void displayWith1Criteria(string column, string value)
{
Console.WriteLine("entering _1_ display method");
dbcontent = new DBtestEntities();
var studienummerQuery = from members in dbcontent.Medlemmer.Include("Retninger")
where column == value
orderby members.Fornavn
select new { Studienr = members.Studienummer, Fornavn = members.Fornavn, Efternavn = members.Efternavn, Email = members.Email, Studiested = members.Studiested, Betaling = members.BetalingsType, Uddannelses_Retning = members.Retninger.retningNavn };
dataGridView1.DataSource = studienummerQuery;
}
Doesn't return any data at all...
column is being called with members.Fornavn (Fornavn - a column name)
value = Anders (one of the data's in Fornavn column)
What I want to do:
My database is loaded into dbcontent using a .edmx file from ABO entity class.
My database consist of 2 tables, "Retninger" and "Medlemmer".
Medlemmer contains columns things like Fornavn(in english, Firstname), Efternavn(Lastname), Studienummer(study no.)
What i would like is a "dynamic" method that can set both which column to be searched in and the value that needs to be searched for in the set column.
When could your expression column == value possibly return true? Only if string.Equals("Fornavn", "Anders") is true.
Doing dynamic linq is hard. Is usually do it this way:
...
where (!useMycolumn1 || member.mycolumn1 == value1)
&&(!useMycolumn2 || member.mycolumn2 == value2)
&&(!useMycolumn3 || member.mycolumn3 == value3)
...
useMycolumn* is a local boolean variable which is set to true or false, depending on whether the certain condition should be tested or not. This way, unused parts of the query are optimized out at compile time.
I think this answer from Shawn Miller to the question you linked is more what you are looking for:
http://www.albahari.com/nutshell/predicatebuilder.html
Are you remembring to call the DataBind() method on the grid? How do you know nothing is being returned?
I think its because of lazy evaluation of LINQ queries.
You can try using .ToList, as below:
dataGridView1.DataSource = studienummerQuery.ToList();
also .DataBind(), if relevant for your object.
Edit:
Lazy Evaluation: This Link, would serve as a good start
Related
I am dealing with a web application. What is asked of me is that when the page loads, that my drop down list displays index 0, with specific properties to display and store.
Based on that, there is a second down list to hold a list.
Next on the selectedIndexChanged event, should my index in ddl1 (I'll call it), the data in ddl2 should change.
The data being populated is all from a database query.
I'm in the process of refactoring, and i am trying to find a way so that I can just pass some data to a bindControls method. I'm having passing a general data type that could be cast based on a boolean value I am also passing to the method.
Here's an example
IQueryable<BankAccount> accountQuery = db.BankAccounts.Where(x => x.ClientId
== clientId && x.AccountNumber != accountNumber);
private void bindControls(DropDownList ddl, string textFieldProp, string
dataFieldProp, boolean isBillPayment, object dataSource)
{
//this is where my confusion is... i don't know how to change the type
//of the object
if(isBillPayment == true)
dataSource = typeof(IQueryable<BankAccount>);
ddlDataSource = dataSource.ToList()
ddlDataTextField = textFieldProp;
ddlDataValueField = dataFieldProp;
ddl.DataBind();
}
I know there HAS to be a way that I can assign this data source to what I want.
the query i posted is just an example of what that data source is going to , i have three different possible table queries from either BankAccounts, TransactionTypes, or Payees.
sorry i should have mentioned that, im sorry to for any confusion with it. Maybe that makes more sense now
Use generics:
private void bindControls<IQueryable<T>>(DropDownList ddl, string textFieldProp, string
dataFieldProp, boolean isBillPayment, IQueryable<T> dataSource)
{
// I don't think you really need this.
// if(isBillPayment == true)
// dataSource = typeof(IQueryable<T>);
ddlDataSource = dataSource.ToList()
ddlDataTextField = textFieldProp;
ddlDataValueField = dataFieldProp;
ddl.DataBind();
}
I would recommend casting .ToList() earlier and passing that to your bindControls() method instead of IQueryable.
... but I don't really understand why you're doing it this way. In my opinion, you don't need your boolean switch.
I have this query in sql and it works fine:
update userinfo set Interest = 0.98 where userid = 313
And I want to do it in linq, so I prepared the following:
public class TableDataDTO
{
public string Columnname { get; set; }
public string Value { get; set; }
public Type DataType { get; set; }
}
Implementation:
TableDataDTO tableData = new TableDataDTO();
tableData.Columnname = "Interest";
tableData.Value = "0.98";
using (dbase instance = new dbase())
{
string predicate = string.Format("it.UserID=={0} set it.{1}={2}" ,
313, tableData.Columnname, tableData.Value);
var uinfo = instance.userinfoes.Where(predicate).FirstOrDefault();
if (uinfo != null)
{
instance.SaveChanges();
return true;
}
}
But it gives me this error:
The query syntax is not valid. Near keyword 'SET'
I will be dealing with different columns, so I need to use linq predicates to minimize the code.
I don't like using any plugins to make this. Hope someone could help.
Edit
I think what I mean is "How to update data in using Dynamic linq"
Edit2
So this is the real scenario. Users/Client can update their information, e.g. First name, Last name, Address, City.. etc.. not at once but capable of updating the info one by one.
So what does it mean? Ok I can create a method that can update the First Name, next is the Last Name, Address and so one.. But if I do this, it will consume a lot of code. If only if there is a code in linq that can do what SQL does in updating data, then I would just need a code that gets the column name and set its value. Hope I'd explain it well.
Edit3
I have changed the question from How to update data in linq using predicates? to How to update column data using sql query in linq? for I misunderstood the real meaning of predicate.
Your predicate should just be the where part of the query (a predicate just returns true or false). Try this:
instance.userinfoes.Where(user => user.userid == 313).First().Interest = 0.98;
You can structure LINQ similar to how you'd structure SQL. Through a combination of Where and ForEach you should be able to update all the rows you need. I.e:
instance.userinfoes.Where(it => it.UserId == 313).ToList()
.ForEach(
it => it.Interest = 0.98M
);
There's not really any way to write SQL-like queries as text and pass them to regular LINQ as far as I know.
See this question for more solutions:
Update all objects in a collection using LINQ
I'm trying to find, then update, a specific DataRow in a DataTable. I've tried a few things based on my searches, and the code below seems to be the closest I can get. The linq will return one row. With that row, I'd like to update column values (Status, StopTime, Duration). I can't for the life of me find how to do this.. I've tried casting, but I'm new to linq and don't see how to update these values.
private DataTable downloadProcStatusTable;
void UpdateDataDownloadProcedureList(ProcedureStats ProcStats)
{
var currentStatRow = from currentStat in downloadProcStatusTable.AsEnumerable()
where currentStat.Field<String>("ProcedureName") == ProcStats.ProcName
select currentStat;
}
Your query as it stands actually gives you an IEnumerable<DataRow>. You need to do this to get the actual row:
var currentStatRow = (from currentStat in downloadProcStatusTable.AsEnumerable()
where currentStat.Field<String>("ProcedureName") == ProcStats.ProcName
select currentStat).SingleOrDefault();
You should then be able to use the currentStatRow variable to modify the column values.
Outline
Load the existing entity from the database (unless you have one that you can re-attach, in which case you could avoid this additional query)
Update the properties as needed
Submit the changes back to the database using SubmitChanges()
Implementation
I wasn't exactly sure where your variables are and the names, but this should give you a good start...
void UpdateDataDownloadProcedureList(ProcedureStats ProcStats)
{
var currentStatRow = (from currentStat in downloadProcStatusTable.AsEnumerable()
where currentStat.Field<String>("ProcedureName") == ProcStats.ProcName
select currentStat).FirstOrDefault();
currentStatRow.Status = ProcStats.Status;
currentStatRow.StopTime = ProcStats.StopTime;
currentStatRow.Duration = ProcStats.Duration;
downloadProcStatusTable.SubmitChanges();
}
Is there a "best practice" way of handling bulk inserts (via LINQ) but discard records that may already be in the table? Or I am going to have to either do a bulk insert into an import table then delete duplicates, or insert one record at a time?
08/26/2010 - EDIT #1:
I am looking at the Intersect and Except methods right now. I am gathering up data from separate sources, converting into a List, want to "compare" to the target DB then INSERT just the NEW records.
List<DTO.GatherACH> allACHes = new List<DTO.GatherACH>();
State.IState myState = null;
State.Factory factory = State.Factory.Instance;
foreach (DTO.Rule rule in Helpers.Config.Rules)
{
myState = factory.CreateState(rule.StateName);
List<DTO.GatherACH> stateACHes = myState.GatherACH();
allACHes.AddRange(stateACHes);
}
List<Model.ACH> newRecords = new List<Model.ACH>(); // Create a disconnected "record set"...
foreach (DTO.GatherACH record in allACHes)
{
var storeInfo = dbZach.StoreInfoes.Where(a => a.StoreCode == record.StoreCode && (a.TypeID == 2 || a.TypeID == 4)).FirstOrDefault();
Model.ACH insertACH = new Model.ACH
{
StoreInfoID = storeInfo.ID,
SourceDatabaseID = (byte)sourceDB.ID,
LoanID = (long)record.LoanID,
PaymentID = (long)record.PaymentID,
LastName = record.LastName,
FirstName = record.FirstName,
MICR = record.MICR,
Amount = (decimal)record.Amount,
CheckDate = record.CheckDate
};
newRecords.Add(insertACH);
}
The above code builds the newRecords list. Now, I am trying to get the records from this List that are not in the DB by comparing on the 3 field Unique Index:
AchExceptComparer myComparer = new AchExceptComparer();
var validRecords = dbZach.ACHes.Intersect(newRecords, myComparer).ToList();
The comparer looks like:
class AchExceptComparer : IEqualityComparer<Model.ACH>
{
public bool Equals(Model.ACH x, Model.ACH y)
{
return (x.LoanID == y.LoanID && x.PaymentID == y.PaymentID && x.SourceDatabaseID == y.SourceDatabaseID);
}
public int GetHashCode(Model.ACH obj)
{
return base.GetHashCode();
}
}
However, I am getting this error:
LINQ to Entities does not recognize the method 'System.Linq.IQueryable1[MisterMoney.LARS.ZACH.Model.ACH] Intersect[ACH](System.Linq.IQueryable1[MisterMoney.LARS.ZACH.Model.ACH], System.Collections.Generic.IEnumerable1[MisterMoney.LARS.ZACH.Model.ACH], System.Collections.Generic.IEqualityComparer1[MisterMoney.LARS.ZACH.Model.ACH])' method, and this method cannot be translated into a store expression.
Any ideas? And yes, this is completely inline with the original question. :)
You can't do bulk inserts with LINQ to SQL (I presume you were referring to LINQ to SQL when you said "LINQ"). However, based on what you're describing, I'd recommend checking out the new MERGE operator of SQL Server 2008.
Inserting, Updating, and Deleting Data by Using MERGE
Another example here.
I recommend you just write the SQL yourself to do the inserting, I find it is a lot faster and you can get it to work exactly how you want it to. When I did something similar to this (just a one-off program) I just used a Dictionary to hold the ID's I had inserted already, to avoid duplicates.
I find LINQ to SQL is good for one record or a small set that does its entire lifespan in the LINQ to SQL.
Or you can try to use SQL Server 2008's Bulk Insert .
One thing to watch out for is if you queue more than 2000 or so records without calling SubmitChanges() - TSQL has a limit on the number of statements per execution, so you cannot simply queue up every record and then call SubmitChanges() as this will throw an SqlException, you need to periodically clear the queue to avoid this.
I'm filling a drop-down list using the following:
var columnNames = db.Mapping.MappingSource.GetModel(typeof(StaffDirectoryDataContext))
.GetMetaType(typeof(Person)).DataMembers;
I'm then converting that to a List<String> to populate a drop down list.
I then want to be able to get a set of results based on the user's selection. For example, if they select "First name" from the drop down list and type "Bob" into the text box I want to run a LINQ query where first name = bob.
I'm probably being thick but I can't find a way! Pseudo code would be...
var q = from x in dc.Persons
where x.[selected column name] == [textbox value]
select x;
Can anybody help? Essentially I have the column name as a String value, and I can't figure out how to tell the LINQ query that that's the column to filter on!
Could do this in ADO.NET with my eyes closed, but determined to use LINQ all the way!!
Thanks in advance.
David Buchanan has posted a solution for this problem using reflection :
msdn forum
I'm not sure you can do this dynamically, but you can do it conditionally. Something like this:
switch(selected column name)
{
case "student_no":
q = q.where(p=>p.StudentNo == value);
break;
case "student_id":
q = q.where(p=>p.StudentId == value);
break;
}
You can iterate through your columns and keep building the wheres. The SQL won't be executed as long as none of the calls force the IQueryable to execute.
I think expression trees are the right way to do this, but I don't know them very well so I'm going to give you the alternate way I would have done this if I didn't feel like learning expression tree building..
public interface IFilter { IEnumerable RetreiveFilter(string filterValue); }
public class FirstNameFilter : IFilter
{
private const string FILTER_TYPE_NAME = "First Name";
public IEnumerable RetreiveFilter(string filterValue)
{
return _myData.Where(person => person.FirstName = filtervalue);
}
public override string ToString()
{
return FILTER_TYPE_NAME;
}
}
Create a class like this for each filter type, and then fill your dropdown with these filters, and when they type info into the filter text, it will execute against the ((IFilter)filterDropDown.SelectedItem).RetreiverFilter(filterTextBox.Text);