LLBLGEN: Load a EntityCollection or List from a datatable - llblgenpro

How do I load an EntityCollection or List(Of Entity) from a DataTable using LLBLGen?

A datatable holds its values in rows and columns whereas a LLBLGen Collection class holds a collection of Entity objects that represent a table in your persistent storage. You can fetch a DataTable of fields that you define with a ResultsetFields via the TypedListDAO. However, going from a DataTable to an EntityCollection is not possible unless your Entity objects are stored in your DataTable.
More likely, you have some keys in your DataTable. If this is the case, you'll need to iterate over the rows of the DataTable, pull out the keys and create new Entity objects from these. Then you can add these Entity objects to your EntityCollection.
// Define the fields that we want to get
ResultsetFields fields = new ResultsetFields(2);
fields.DefineField(EmployeeFields.EmployeeId, 0);
fields.DefineField(EmployeeFields.Name, 1);
// Fetch the data from the db and stuff into the datatable
DataTable dt = new DataTable();
TypedListDAO dao = new TypedListDAO();
dao.GetMultiAsDataTable(fields, dt, 0, null, null, null, false, null, null, 0, 0);
// We now have a datatable with "EmployeeId | Name"
// Create a new (empty) collection class to hold all of the EmployeeEntity objects we'll create
EmployeeCollection employees = new EmployeeCollection();
EmployeeEntity employee;
foreach(DataRow row in dt.Rows)
{
// Make sure the employeeId we are getting out of the DataTable row is at least a valid long
long employeeId;
if(long.TryParse(row["EmployeeId"].ToString(), out employeeId))
{
// ok-looking long value, create the Employee entity object
employee = new EmployeeEntity(employeeId);
// might want to check if this is .IsNew to check if it is a valid object
}
else
{
throw new Exception("Not a valid EmployeeId!");
}
// Add the object to the collection
employees.Add(employee);
}
// now you have a collection of employee objects...
employees.DoStuff();

Related

12.1.3. OAF. How to join 2 View Object which populating programmatically?

I have 2 View Object which populating programmatically, i.e. this objects don't have a SQL query in Query Statement region. There is HeaderVO and LinesVO. My task is display advanced table in advanced table. And this advanced tables based on HeaderVO and LinesVO. If I use View Link than the HeaderVO table displays data but LinesVO table displays only "No search conducted". It's logically and I understand why it is.
But how can I connected this 2 tables (View Objects)?
As the VO populates programatically, you can try by creating the View Link between these VOs also programatically. You can use the below method for the same :
Assume Master VO as deptVO and Detail VO as empVO.
// Build an attribute array, consisting of deptVO.DeptNum for Master VO
AttributeDef[] deptAttrs = new AttributeDef[1];
deptAttrs[0] = deptVO.findAttributeDef("DeptNum");
// Build an attribute array, consisting of empVO.DeptNum for Detail VO
AttributeDef[] empAttrs = new Attributedef[1];
empAttrs[0] = empVO.findAttributeDef("DeptNum");
ViewLink vl = myAM.createViewLinkBetweenViewObjects("yourVLName",
"VLAccessor", //accessor name
deptVO, //master VO
deptAttrs, //master VO attribute
empVO, //detail VO
empAttrs, //detail VO attribute
null); //association clause
In order to have a Master-Detail relationship in OAF advancedTable component, the detail VO child attribute must be correctly mapped. As you are programmatically defined Master VO and Child VO, please ensure that this step has been completed. Are you creating advancedTable declaratively or programmatically?
createViewLinkBetweenViewObjects API
ViewObject voDept = am.createViewObject("MyDeptVO", "package1.DeptView");
ViewObject voEmp = am.createViewObject("MyEmpVO", "package1.EmpView");
AttributeDef[] deptLinkAttrs = new AttributeDef[] { voDept.findAttributeDef("Deptno") };
AttributeDef[] empLinkAttrs = new AttributeDef[] { voEmp.findAttributeDef("Deptno") };
ViewLink vl = am.createViewLinkFromEntityAssocName("MyDeptEmpLink",
"Employees",
voDept, deptLinkAttrs,
voEmp, empLinkAttrs,
null);

Getting Column Names of a Table Ado.NET

I'm trying to get column names of a table, but it only returns the column names such as TABLE_SCHEMA,TABLE_NAME,TABLE_CATALOG,TABLE_TYPE.
Here's the code;
DataTable table = con.GetSchema("Tables", new string[] { null, null, "Contact" });
var columnNames = (from DataRow r in table.Rows
from DataColumn c in table.Columns
select c.ColumnName).ToList();
I need to save the names in a list.Thanks.
try this:
DataTable table = con.GetSchema("Columns", new string[] { null, null, "Contact" });
you have to specify Columns instead of Tables as collectionName ...
you should also change your linq query to something like this:
var columnNames = (from r in tab.AsEnumerable()
select r.Field<string>("COLUMN_NAME")).ToList();

Linq ResultSet to DataTable

I have a SQL Database which I imported as a ADO.NET Entity Data Model. I then populate a DataGridView using Linq. I extended two of the tables with extra columns that are calculated from other tables. For instance, I have a table Orders that has fields OrderNumber, DateApproved and RequestorID and so on. I also have a table that is the OrderDetails with Fields like SKU, OrderNUmber and QuanityOrdered. I coded a new column IsBackOrdered for the Orders Table that calculates if any Item(SKU) from the OrderDetails is backordered.
When I bound the table Orders to the DataGridView.DataSource everything works as expected. I was then directed to create a search filter for the table.
I tried to map BindingSource to the Linq query but BindingSource is expecting a DataTable. I found a neat little method that converts Linq ResultSet to a DataTable (Code below) however it barfs on my custom fields (Columns) at this line: dr[pi.Name] = pi.GetValue(rec, null) ?? DBNull.Value;
Thanks in advance for any of your view or helpful insights you would care to offer.
public static DataTable LinqToDataTable<T>(IEnumerable<T> varlist)
{
var dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null)
return dtReturn;
foreach (T rec in varlist)
{
// Use reflection to get property names, to create table, Only first time, others will follow
if (oProps == null)
{
oProps = rec.GetType().GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) ?? DBNull.Value;
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
DataSource property of the BindingSource doesn't expect DataTable. It's of type object, so you may use any list as data source. But in this case to be able to filter it you should either implement IBindingListView or use BindingList. The second case is easier of course. Take a look here for more information.

How to declare the result of query in LINQ to Entities

I just started using MS entity framework and have the following problem with LINQ. I will simplify my problem to make it clearer; let's say that I have three tables in SQL Server database:
CustomerData (PK is CustomerId, the table also has some twenty columns to hold customer data).
CustomerData1 (holds some data for the customer in one to one relationship).
CustomerData2 (also holds some data for the customer in one to one relationship).
I know the data with one to one relationship should better be in the same table, but this is some corporate db and it is not possible to alter the original table (so all our data should be in the separate tables).
Now I want to display a list of customer with their data from CustomerData table and add some data columns from CustomerData1 via join.
On the other hand, I want to display a list of customers and add some data from the other table CustomerData2 via join.
So the data is basically the same both times except that in the first case the result includes some columns from CustomerData1 and in the second case some data from CustomerData2 table.
So I created the class Customer with properties for all relevant columns in CustomerData table and added properties for columns that should be included from CustomerData1 and properties that should be included from CustomerData2.
All columns should be included each time, except that when first call will be made the properties that map to CustomerData2 table will be empty and during the second call the properties that map to CustomerData1 table will be empty.
For this I wanted to create one function so I tried to create it like this:
Input parameter in function is whether data from CustomerData1 or CustomerData2 is included.
if (firstList)
{
var query1 = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
if (secondList)
{
var query2 = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
So this code gives me the anonymous type based on the input parameter. Now I want to create Customer objects and order it (order is always the same, it does not depend on input parameter). So I want to create a list of ordered customers and include additional data based on the input parameter.
var query3 = <previous_query_variable>.Select(f => new Customer {
Id = f.obj.CustomerId,
Name = f.obj.CustomerName,
... other columns from Customer table (a lot of them)
//and then add some additional columns based on the input parameter
Data1 = f.rel.someDataFromCustomer1, //only when firstList == true, otherwise empty
Data2 = f.rel.someDataFromCustomer2 //only when secondList == true, otherwise empty
}).OrderBy(f => f.Name); //order by customer name
Of course this does not compile, since both vars are inside if statements. I know I could copy this last statement (var query3 = ...) inside both if statements and include only relevant assignments (Data1 or Data2), but I don't want to assign properties that map to CustomerData table twice (once in both if statements) nor I want to order twice.
How can I solve this problem? I am using .NET 4.
You cannot declare a variable for an anonymous type up-front, i.e. before your two if statements. (Something like var query = null is not supported.) You will have to create a helper type and project into it, like so:
public class ProjectedCustomerData
{
public CustomerData CustomerData { get; set; }
public CustomerData1 CustomerData1 { get; set; }
public CustomerData2 CustomerData2 { get; set; }
}
And then the projection:
IQueryable<ProjectedCustomerData> resultQuery = null;
if (firstList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData1 = rel
};
}
if (secondList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData2 = rel
};
}
var query3 = resultQuery.Select(f => new Customer {
Id = f.CustomerData.CustomerId,
Name = f.CustomerData.CustomerName,
// ...
Data1 = f.CustomerData1.someDataFromCustomer1,
Data2 = f.CustomerData2.someDataFromCustomer2
}).OrderBy(f => f.Name);
I am not sure if Customer is an entity in your model or only a class you are using for your projection. If it's an entity you have to change the last code because you cannot project into an entity (basically you would need another helper type for your projection).

Auditing in Entity Framework

After going through Entity Framework I have a couple of questions on implementing auditing in Entity Framework.
I want to store each column values that is created or updated to a different audit table.
Right now I am calling SaveChanges(false) to save the records in the DB(still the changes in context is not reset). Then get the added | modified records and loop through the GetObjectStateEntries. But don't know how to get the values of the columns where their values are filled by stored proc. ie, createdate, modifieddate etc.
Below is the sample code I am working on it.
// Get the changed entires( ie, records)
IEnumerable<ObjectStateEntry> changes = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
// Iterate each ObjectStateEntry( for each record in the update/modified collection)
foreach (ObjectStateEntry entry in changes)
{
// Iterate the columns in each record and get thier old and new value respectively
foreach (var columnName in entry.GetModifiedProperties())
{
string oldValue = entry.OriginalValues[columnName].ToString();
string newValue = entry.CurrentValues[columnName].ToString();
// Do Some Auditing by sending entityname, columnname, oldvalue, newvalue
}
}
changes = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added);
foreach (ObjectStateEntry entry in changes)
{
if (entry.IsRelationship) continue;
var columnNames = (from p in entry.EntitySet.ElementType.Members
select p.Name).ToList();
foreach (var columnName in columnNames)
{
string newValue = entry.CurrentValues[columnName].ToString();
// Do Some Auditing by sending entityname, columnname, value
}
}
Here you have two basic options:
Do it at the database level
Do it in the c# code
Doing it at the data base level, means using triggers. In that case there is no difference if you are using enterprise library or another data access technology.
To do it in the C# code you would add a log table to your datamodel, and write the changes to the log table. When you do a save changes both the changes to the data and the information which you wrote to the log table would be saved.
Are you inserting the new record using a stored proc? If not (i.e. you are newing up an object, setting values, inserting on submit and then saving changes the new object id will be automatically loaded into the id property of the object you created. If you are using a stored proc to do the insert then you need to return the ##IDENTITY from the proc as a return value.
EX:
StoreDateContext db = new StoreDataContext(connString);
Product p = new Product();
p.Name = "Hello Kitty Back Scratcher";
p.CategoryId = 5;
db.Products.Add(p);
try
{
db.SaveChanges();
//p.Id is now set
return p.Id;
}
finally
{
db.Dispose;
}

Resources