I found this sample from here :
NWDataContext context = new NWDataContext();
var model = context.Mapping;
//get all tables
foreach (var mt in model.GetTables())
{
Console.WriteLine("Getting data " + mt.TableName);
//generate a sql statment for each table - just grab the first 20
string sql = String.Format("Select Top 20 * from {0} ", mt.TableName);
var data = context.ExecuteQuery(mt.RowType.Type, sql);
//data is here now. Lets print it on the console
foreach (var item in data)
{
Console.WriteLine(item.ToString());
}
}
Console.ReadLine();
Is there a way to get 10 rows without using Sql string?
for example something similar to this (it gets table associations, I am after 10 (N) rows of table data instead of table associations):
var tableData = from t in this.Mapping.GetTables()
select new
{
t.TableName,
Associations =
from a in t.RowType.Associations
select new
{
a.ThisMember.Name,
TypeName = a.ThisMember.Type.Name
}
};
tableData.Dump();
To do this, you need to call context.GetTable on the Type:
from metaTable in context.Mapping.GetTables()
let table = (IQueryable<object>) context.GetTable (metaTable.RowType.Type)
select table.Take(10)
Bear in mind that your examples are relevant to LINQ to SQL, not EF (as the title suggests).
EntityFramework returns IEnumerables when you get data from the database. That means unless you enumerate through it (like get count, ToList(), etc. Lazy loading actually) data will not be fetched from the database.
So here is an example,
var database = new SomeDatabase(connectionString);
var tableRows = database.Context.SomeTableName;
var result = new List<SomeDataType>();
var count = 0;
foreach (var tableRow in tableRows)
{
result.Add(tableRow);
count++;
if (count == 10) break;
}
Or
var result = database.ContextSomeTableName.Take(10).ToList();
In this example, only 10 records will be fetched from database.
But if you do this,
var tableRows = database.Context.SomeTableName.ToList();
You will fetch whole rows from that table (Note ToList()),
Related
I have this method that saves an entity with its related items (many-to-many relationship),
private static void Save<T>(TbCommonHistoryLog log, List<T> lstDetails) where T : IHasSerial
{
foreach (var item in lstDetails.OrderBy(x => x.Serial))
{
var ser = SerializeObject(item);
var record = oContext.TbHistoryLog_Lists.FirstOrDefault(x => x.ListObjectJson == ser);
if (record == null) //add new list item
{
TbCommonHistoryLog_Lists listObject = new TbCommonHistoryLog_Lists()
{
ListObjectJson = SerializeObject(item)
};
var details = new TbCommonHistoryLogDetails { TbHistoryLog = log, TbHistoryLog_Lists = listObject };
oContext.TbHistoryLogDetails.Add(details);
}
else //attach an existing list item
{
var o = oContext.TbHistoryLog_Lists.Find(record.Id);
oContext.TbHistoryLog_Lists.Attach(o);
var details = new TbCommonHistoryLogDetails { TbHistoryLog = log, TbHistoryLog_Lists = o };
oContext.TbHistoryLogDetails.Add(details);
}
}
oContext.BulkSaveChanges();
}
I have two tables: TbCommonHistoryLog, TbCommonHistoryLog_Lists, that are in many to many relationship, the joining table is TbCommonHistoryLogDetails,
What I'm doing here is an auditing for master-detail models, all audits are serialized to JSON in DB, I save the head object in the TbCommonHistoryLog table, and every list item in the TbHistoryLog_Lists table, in the mthod above I check if the list item is already exists in the database or not to avoid duplicating.
but this process takes more than 15 seconds which is a very long time, I can't figure out what am I doing wrong here.. please help?
For every single item in collection you're querying database. My suggestion is to save records in var, then ask the variable if the item is in database.
var databaseRecords = oContext.TbHistoryLog_Lists.ToList();
Then in the loop:
var record = databaseRecords.FirstOrDefault(x => x.ListObjectJson == ser);
I have a datatable in memory and I need to select some records from it, walk through the records making changes to fields and they same the changes back to the datatable. I can do this with filters, views, and sql but I'm trying to do it in Linq.
var results = (from rows in dtTheRows.AsEnumerable()
select new
{
rows.Job,
}).Distinct();
foreach (var row in results)
{
firstRow = true;
thisOnHand = 0;
var here = from thisRow in dtTheRows.AsEnumerable()
orderby thisRow.PromisedDate
select new
{
thisRow.OnHandQuantity,
thisRow.Balance,
thisRow.RemainingQuantity
};
foreach(var theRow in here)
{
// business logic here ...
theRow.OnHandQuantity = 5;
} // foreach ...
The first linq query and foreach are gain the list of subsets of data to be considered. I include it here in case it is relevant. My problem is at this line:
heRow.OnHandQuantity = 5;
My error is:
"Error 19 Property or indexer 'AnonymousType#1.OnHandQuantity' cannot be assigned to -- it is read only"
What am I missing here? Can I update this query back into the original datatable?
var here = from thisRow in dtTheRows.AsEnumerable()
orderby thisRow.PromisedDate
select new
{
thisRow.OnHandQuantity,
thisRow.Balance,
thisRow.RemainingQuantity
};
Instead of passing three variables in select, pass thisRow itself. That may solve error on statement - theRow.OnHandQuantity = 5;
The error is self descriptive, you can't update/modify an anonymous type. You have to return the original entity you want to modify from your query.
select thisRow;
instead of
select new
{
thisRow.OnHandQuantity,
thisRow.Balance,
thisRow.RemainingQuantity
};
i have some List that hold 1 or more Guid.
var getMyfirstListGuids = (from dlist in db.MyTable
where dlist.id == theid
select dlist).ToList();
List<MyfirstList> myfirstList = new List<MyfirstList>();
foreach (var item in myLandingPageList)
{
Guid theguid = new Guid(item.guid);
MyfirstList addnewRow = new MyfirstList();
addnewRow.LpGuid = new Guid(theguid);
myfirstList.Add(addnewRow);
}
Now i have a list with 1 or more guids.
my next step is to make list with data from SQL by the first list guids.
In the SQL could be 1 row or more for each guid. with one row result i can guess what to do. but if there is many results i dont have an idea.
Okay so you wanna do it like this:
List<SecondListGUID> secondListGUID = new List<SecondListGUID>();
foreach (var item in myfirstList)
{
for(int i = 0; i<_yourDBEntity.GUIDs.Count(); i++)
{
if(item.LpGuid == _yourDBEntity.GUIDs[i].GUID)
secondListGUID.add(
new SecondListGUID() {
// add the corresponding GUID's here
});
}
}
Basically you have to do a foreach through your first List and then do a for loop (or foreach - whichever you prefer) through your DB table (entity in this case if you're using Entity framework) and simply compare the GUID's from your DB table and if they match you'll wanna add the item to your third list.
P.S. I've worked with the informations that you've provided, you can change the 2nd list type into the one you need, and change your entity framwork data model name into the one you actually use :)
You can try this
List<Guid>getMyfirstListGuids = new List<Guid>();
getMyfirstListGuids.addRange(from dlist in db.MyTable
where dlist.id == theid
select dlist).ToList());
List<MySecList> mySecList = new List<MySecList>();
mySecList.AddRange(_db.myLandingPageList.Where(p => p.Guid.Any(x => getMyfirstListGuids.Contains(x));
Straight to the point, I am trying to make an application so that the user can search through their CRM system without going onto CRM. I have managed to retrieve the record but when i try to put the record into a list using the records attributes I am only recieving the Keys.
Here is the code:
EntityCollection retrieved = _service.RetrieveMultiple(query);
foreach (var c in retrieved.Entities)
{
foreach (KeyValuePair<String, Object> attribute in c.Attributes)
{
lstRecordDetails.Items.Add(string.Format(attribute.Key + ": " + attribute.Value));
}
}
This only displays the recordID and the Record Name, I understand these are both the primary keys oh the record and i know i could use c.Attributes["description"] for the description but is there a way that i can get all the fields from the record and display them in the list?
Edit: Details on the query
QueryByAttribute query = new QueryByAttribute(entity);
query.ColumnSet = new ColumnSet(field);
query.Attributes.AddRange(field);
query.Values.AddRange(selected);
The way you can retrieve all the columns of an entity is
query.ColumnSet = new ColumnSet(true);
However, be careful with this, because query all columns has an impact on the system (you should always retrieve explicitly the columns you need).
RetrieveMultipleRequest retrieve = new RetrieveMultipleRequest();
retrieve.Query = query;
retrieve.ReturnDynamicEntities = true;
retrieved = (RetrieveMultipleResponse)Service.Execute(retrieve);
foreach(var dynEntity in retrieved.BusinessEntityCollection)
{
foreach (var prop in dynEntity.Properties)
{
lstRecordDetails.Items.Add(string.Format("{0}:{1}", prop.Name, prop.Value);
}
}
Is it possible to dynamically limit the number of columns returned from a LINQ to SQL query?
I have a database SQL View with over 50 columns. My app has a domain object with over 50 properties, one for each column. In my winforms project I bind a list of domain objects to a grid. By default only a few of the columns are visible however the user can turn on/off any of the columns.
Users are complaining the grid takes too long to load. I captured the LINQ generated SQL query then executed it within SQL Server Management Studio and verified its slow. If I alter the SQL statement, removing all the invisible columns, it runs almost instantly. There is a direct correlation between performance and the number of columns in the query.
I'm wondering if its possible to dynamically alter the number of columns returned from the LINQ generated SQL query? For example, here is what my code currently looks like:
public List<Entity> GetEntities()
{
using (var context = new CensusEntities())
{
return (from e in context.Entities
select e).ToList();
}
}
The context.Entities object was generated from a SQL View that contains over 50 columns so when the above executes it generates SQL like "SELECT Col1, Col2, Col3, ... Col50 FROM Entity INNER JOIN...". I would like to change the method signature to look like this:
public List<Entity> GetEntities(string[] visibleColumns)
{
using (var context = new CensusEntities())
{
return (from e in context.Entities
select e).ToList();
}
}
I'm not sure how to alter the body of this method to change the generated SQL statement to only return the column values I care about, all others can be NULL.
Something like this should work:
List<string> columns = new List<string>();
columns.Add("EmployeeID");
columns.Add("HireDate");
columns.Add("City");
Add columns to your list ^.
var result = Class.ReturnList(columns);
Pass the List to a method ^.
public static List<Entity> ReturnList(List<string> VisibleColumns)
{
StringBuilder SqlStatement = new StringBuilder();
SqlStatement.Append("Select ");
for (int i = 0; i < VisibleColumns.Count; i++)
{
if (i == VisibleColumns.Count - 1)
{
SqlStatement.Append(VisibleColumns[i]);
}
else
{
SqlStatement.Append(VisibleColumns[i]);
SqlStatement.Append(",");
}
}
SqlStatement.Append(" FROM Entity");
using (var ctx = new DataClasses1DataContext())
{
var result = ctx.ExecuteQuery<Entity>(SqlStatement.ToString());
return result.ToList();
}
}
This basically just makes a SELECT statement with all the fields you passed in with the VisibleColumns list.
In this case, the SQL statement that will be generated by the strings in the VisibleColumns list is:
Select EmployeeID, HireDate, City From Employee
(note: i used the Northwind database to try this out, hence the EmployeeID etc column names. You should replace them with your own, obviously.)
It is not trivial to do this dynamically, but if you have a limited set of combinations of columns you want to retreive you can do an explicit select like this:
public List<Entity> GetEntities()
{
using (var context = new CensusEntities())
{
return (from e in context.Entities
select new
{
col1 = e.col1,
col4 = e.col4,
col5 = e.col5,
}
).ToList()
.Select(x=>new Entity{col1 = x.col1, col4 = x.col4, col5 = x.col5}).ToList();
}
}
The extra select step is necessary because LINQ2SQL won't create partial entities for you.
Create a method for each common combination of columns (especially the initial) the users wants to retrieve.
However to make this dynamic you can build a query with you entity stored as a property in an anonymous class and collect your result properties in another anonymous class in second property in the same anonymous class. Finally you select your entities from the collected objects into objects of the correct type.
public List<Entity> GetEntities()
{
using (var context = new CensusEntities())
{
var combinedResult = (from e in context.Entities
select new {
Entity = e,
CollectedValues = new
{
// Insert default values of the correct type as placeholders
col1 = 0, // or "" for string or false for bool
col2 = 0, // or "" for string or false for bool
// ...
col49 = 0, // or "" for string or false for bool
col50 = 0, // or "" for string or false for bool
}
);
// Then copy each requested property
// col1
if (useCol1)
{
var combinedResult = (from e in combinedResult
select new {
Entity = e,
CollectedValues = new
{
col1 = e.Enitity.col1, // <-- here we update with the real value
col2 = e.CollectedValues.col2, // <-- here we just use any previous value
// ...
col49 = e.CollectedValues.col49, // <-- here we just use any previous value
col50 = e.CollectedValues.col50, // <-- here we just use any previous value }
);
}
// col2
if (useCol2)
{
// same as last time
col1 = e.CollectedValues.col1, // <-- here we just use any previous value
col2 = e.Enitity.col2, // <-- here we update with the real value
// ...
}
// repeat for all columns, update the column you want to fetch
// Just get the collected objects, discard the temporary
// Entity property. When the query is executed here only
// The properties we actually have used from the Entity object
// will be fetched from the database and mapped.
return combinedResult.Select(x => x.CollectedValues).ToList()
.Select(x=>new Entity{col1 = x.col1, col2 = x.col2, ... col50 = x.col50}).ToList();
}
}
There will be lots of code, and a pain to maintain, but it should work.
If you are going this route I suggest that you build a code generator that builds this code with reflection from your LINQ context.
Try something like this
using (var context = new CensusEntities())
{
var q = from e in context.Entities
select e.myfield1,e.myfield2;
return q.Tolist();
}
The resulting query should be lighter and also all the data conversion that goes underneath.
But if you really need to build dynamic input, I think some dynamic sql should be involved. So
build the dynamic SQL and get a data table
use a datatable to a dynamic object conversion as shown here
How can I convert a DataTable into a Dynamic object?
BTW a lot of hard work, I think you should considered using the first block of code.