How can I create a DateTime value in a Linq Query? - vb.net

I am trying to create a query in Linq to Entities. I want it to return objects that include a DateTime property derived from strings in the table I am querying. The data (in SQL Server) has a string date field (in the database it appears as VARCHAR(8)) called date_occurred. It has a String time field (varchar(6)) called time_occurred.
An example of the contents of date_occurred is "20131007" to represent Oct. 7, 2013. An example of the contents of time_occurred is "145710" to mean 10 seconds after 2:57pm.
I have tried two methods that don't work:
Dim ATQuery = From e In EntityContext.vwSecAppAuditToday
Order By e.date_occurred, e.time_occurred
Select New AuditEntry With {
.EventTime = DateTime.ParseExact(Trim(e.date_occurred) & Trim(e.time_occurred), "yyyyMMddHHmmss", CultureInfo.InvariantCulture),
.ServerName = e.server_name
}
This throws a NotSupportedException with a message stating: "LINQ to Entities does not recognize the method 'System.DateTime ParseExact(System.String, System.String, System.IFormatProvider)' method, and this method cannot be translated into a store expression."
Before that, I tried:
Dim ATQuery = From e In EntityContext.vwSecAppAuditToday
Order By e.date_occurred, e.time_occurred
Select New AuditEntry With {
.EventTime = New DateTime(Integer.Parse(e.date_occurred.Substring(0, 4)),
Integer.Parse(e.date_occurred.Substring(4, 2)),
Integer.Parse(e.date_occurred.Substring(6, 2)),
Integer.Parse(e.time_occurred.Substring(0, 2)),
Integer.Parse(e.time_occurred.Substring(2, 2)),
Integer.Parse(e.time_occurred.Substring(4, 2))),
.ServerName = e.server_name
}
This also throws a NotSupportedException. In this case, the message states: "Only parameterless constructors and initializers are supported in LINQ to Entities."
Is what I am trying to do possible using Linq to Entities?
Edit: Comment Alert
For those who read this post later, Moho and Matt Johnson have made especially helpful comments. I have marked these with +1.

Select an anonymous class that contains the fields of interest (called a projection), then create DateTime struct per item after the IQueryable has been enumerated:
Dim ATQuery = From e In EntityContext.vwSecAppAuditToday
Order By e.date_occurred, e.time_occurred
Select New With {
.DateOccurred = e.date_occurred,
.TimeOccurred = e.time_occurred,
.ServerName = e.server_name
}
Dim q2 = From e In ATQuery.ToArray()
Select New AuditEntry With {
.EventTime = DateTime.ParseExact(Trim(e.DateOccurred) & Trim(e.TimeOccurred), "yyyyMMddHHmmss", CultureInfo.InvariantCulture),
.ServerName = e.ServerName
}

Your New DateTime contains only integer, so it looks like 20131008011300 (for 2013/10/08 01:13:00)
/ between date, : between time and a space between date and time are missed

Related

Return type of Linq on Datatable

I have a datatable with two columns ID & Role.
Same ID can have multiple roles.
I need to convert this table to a comma separated grouped table.
I am trying to use following query but unable to solve the issue.
LINQ:
From row As DataRow In dtData.Rows.Cast(Of DataRow)
Group row By id = row.Field(Of Integer)("ID") Into Group
Select ID, Role = String.Join(",", From i In Group Select i.Field(Of String)("Role"))
Issue
Any help will be appreciated.
Update 1:
Table structure
Needed table Structure
You could create a linq like in your comments just that this returns a list of arrays of string:
Here is the code:
(From row As DataRow In myDatatable
Group row By id = row.Field(Of String)("ID") Into Group
Select {id, String.Join(",", From i In Group Select i.Field(Of String)("Role"))}).ToList
If you need the result in a datatable you can build a new datatable
Make a for each of result and use the activity Add data row. In ArrayRow add the item and in DataTable the new data table
If you use the activity Output data table you can see the results
I am kind of confused by what you are wanting as the ultimate outcome. An idea that may guide you but not be exactly what you want is you can change a DataTable to an anonymous projection and then get what you want out of that. You can do a 'Select' off a DataTable which enters into an extension method of 'what' do you want to select. If I was to do a new {} without any class or container object after the 'new' I would be scoped to just a method or not. This is a good advantage when you want to mold something for a specific use in just a single method to use tailored to a specific view.
static void Main(string[] args)
{
DataTable d = new DataTable();
d.Columns.Add("ItemName", typeof(string));
d.Columns.Add("MinValue", typeof(float));
d.Columns.Add("MaxValue", typeof(float));
d.Rows.Add("Widget1", 0.1, 0.2);
d.Rows.Add("Widget2", 0.2, 0.4);
d.Rows.Add("Widget3", 0.1, 0.2);
var dataTable = d.AsEnumerable();
//What do you want to select? The new {} without an indicator means anonymous type projection. This will exist only in
// the scope listed.
var data = dataTable.Select(x => new { ItemName = x[0], MinValue = x[1], MaxValue = x[2] }).ToList();
//My 'data' type is now well typed for it's properties in the scope it's in.
var joined = String.Join(", ", data.Select(x => x.ItemName).ToList());
Console.WriteLine(joined);
Console.WriteLine($"{data.Count}");
Console.ReadLine();
}
EDIT 1-26-18
Strange I thought I updated the code yesterday. To get a reusable object you could bind your front end to, you just make a POCO like so:
public class Foo
{
public string Bar { get; set; }
public string MinAndMax { get; set; }
}
While you could make another DataTable, frankly DataTables are like WinForms. They get the job done, but they are archaic and not friendly to do Linq with as easily as just a well formed POCO. And if you get into using Linq it will play better with well formed objects and they are easy to create.
var data = dataTable.Select(x => new Foo { Bar = x[0].ToString(), MinAndMax = $"{x[1]} {x[2]}" }).ToList();
//My 'data' type is now well typed for 'Foo' class and it's properties in the scope it's in.
var joined = String.Join(", ", data.Select(x => $"{x.Bar} {x.MinAndMax}").ToList());

Power Builder 10.5 user object array to datawindow table

I am new to Power Builder and I would like to ask how can I represent my objects in a table form. For example, given an ArrayList in java I have implemented the code like this:
table = new JTable();
scrollPane.setViewportView(table);
DefaultTableModel tableModel =
new DefaultTableModel(
new String[] {
"ScheduleNo",
"Start Date",
"End Date",
"No of days",
"Principal Expected",
"Interest Expected",
"EMI amount",
"Factor",
"MeanFactor"}
, 0);
for (Schedule s : pf.getSchedules()){
Integer schNo = s.getScheduleNo();
String startDate = df.format(s.getStartDate());
String endDate = df.format(s.getEndDate());
Integer noofdays = s.getNoOfDays();
String prinExp = String.format("%.2f", s.getPrincipalAmt());
String intExp = String.format("%.2f", s.getInterestAmt());
String emi = String.format("%.2f", s.getAmortizedAmount());
String factor = String.format("%.6f", s.getFactor());
String mean = String.format("%.6f", s.getProductByFactor());
Object[]data = {schNo, startDate, endDate, noofdays, prinExp, intExp,
emi, factor, mean};
tableModel.addRow(data);
}
table.setModel(tableModel);
But I cannot find a way to do it in PowerBuilder without having a connection to a database and pick the data from there which is totally not the case.
The data come from an User Object array[] and have exactly the same form like in the Java example above.
Without really knowing what you are trying to accomplish it appears to me that you could use a 'normal' PowerBuilder datawindow but when you define it you make it's datasource as external. This type of datawindow does not require a connection to a database. You define the 'fields' of the datasource as strings, numeric, etc. when you create it.
In code you can create a datawindow (or datastore for that matter) control, assign the external datasource datawindow object to it, insert a row, then populate the fields with data of the corresponding datatype.
Example usage:
datawindow ldw
long llrow
ldw = CREATE datawindow
ldw.dataobject = 'myExternalDatawindowObject'
llrow = ldw.insertrow(0)
ldw.setitem(llrow,'stringcolumn','my example string')
ldw.setitem(llrow,'numericcolumn',1234)
It's been a while since I used PowerBuilder, but IIRC you should be able to use a DataStore without having a database connection.

Calling a function within Entity Framework Select

A property from my object (oJobs) is as follows:
Private _brandlist As List(Of DAL.Brand)
Public Property PostBrandList() As List(Of DAL.Brand)
Get
Return _brandlist
End Get
Set(ByVal value As List(Of DAL.Brand))
_brandlist = value
End Set
End Property
In the database, the brand list is stored as a string separated by comma e.g. the column 'brands' can be a string '3,45,2' where each number represents an id of a brand stored in another table.
my select query is as below:
Dim jobposts As List(Of oJobs) = From j In db.JobPostings
Select New oJobs With { 'hiding all others for code brevity
.PostBrandList = 'problem is here'
}
Since j.BrandList will return a string, I will need to split that string and for each number, run another query to finally return and assign a List(Of DAL.Brand) into .PostBrandList
For those who might ask "what have you tried?",
I have run the query, then did a for each to add the list of brands later - succeeded but not optimal
Coded a function that takes the list as a parameter and returns a separate list of objects - very silly.
Also, I am not allowed to normalize the DB :(
Not tested and might need some tweaking but heres one idea. you will also need to change your property to an IEnumerable rather than List. Because the second linq query is embedded within the first, I believe it should execute it all as one query, but you should check it to make sure.
Dim jobposts As List(Of oJobs) = From j In db.JobPostings
Select New oJobs With { 'hiding all others for code brevity
.PostBrandList = From b In db.Brands Where j.Brands = b.ID Or j.Brands.StartsWith(b.ID & ",") Or j.Brands.EndsWith("," & b.ID) Or j.Brands.Contains("," & b.ID & ",") Select b
}
In c# you can use
.Select(x=>new {x.BrandList})
.ToList() //Materialize first before calling function
.Select(x=> new oJobs{
PostBrandList =
db.Brands.Where(z=>
x.BrandList
.Split(',')
.Select(y=>int.Parse(y.Trim()))
.Contains(z.Id))
.ToList()
});
Note that you must materialize entity first before calling String.Split
I don't know how to translate that to VB.NET.
Of course it will cause SELECT n+1 problem because you can't use join.
If you can't normalize table, my other suggestion is to create indexed view (sql server), so you can use join and improve performance.
Indexed view https://msdn.microsoft.com/en-us/library/ms191432.aspx
You could try it with the Let statement:
Dim jobposts As List(Of oJobs) = From j In db.JobPostings
/* li in the LINQ Statement represents one string value from the BrandList list */
Let postBrandElemsList = j.BrandList.Split(',').Select(Function(li) New DAL.Brand With { ... /* Field initializatione of the Class DAL.Brand here */ }
Select New oJobs With
{
.PostBrandList = postBrandElemsList
}
I'm sorry for the probably bad VB.NET syntax, you should check this when implementing it in your code.
Maybe you would just want to use the Split function on the column brands into an array and iterate through the result, using the Find function to retrieve the brand objects?

LINQ expression to expression tree via API in VB

I have a relatively simple LINQ expression which I need to convert into VB expression tree syntax. This is likely an easy task for folks that are familiar, but I am new to the realm of LINQ expression trees.
In my samples, you see a "New Int16() {}" array. That value must be parameterized at run-time with an array of values from another code element.
my query is:
from i in tblInstitutions
let ChildHasCategory = i.tblInstCtgyHistories.Where(Function(CtgyHist) CtgyHist.EndDate is Nothing AND ( (New Int16() {32,35,38,34}).Contains(CtgyHist.InstCtgyCodeFK)))
where ChildHasCategory.Any()
select i
Which can also be represented as:
tblInstitutions
.Select (i => new {
i = i,
ChildHasCategory = (IEnumerable<tblInstCtgyHistory>)(i.tblInstCtgyHistories)
.Where (
CtgyHist =>
((CtgyHist.EndDate == null) &
(IEnumerable<Int16>)(new Int16[] { 32, 35, 38, 34 } ).Contains (CtgyHist.InstCtgyCodeFK)
)
)
}
)
.Where ($VB$It => $VB$It.ChildHasCategory.Any ())
.Select ($VB$It => $VB$It.i)
This is going to be used in the context of a custom filter in an ASP.NET Dynamic Data web application. I'd like to mimic the default approach.
A sample of one of the other dynamic filter code-behind is:
Public Overrides Function GetQueryable(source As IQueryable) As IQueryable
Dim value = TextBox1.Text
If String.IsNullOrWhiteSpace(value) Then
Return source
End If
If DefaultValues IsNot Nothing Then
DefaultValues(Column.Name) = value
End If
Dim parameter = Expression.Parameter(source.ElementType)
Dim columnProperty = Expression.PropertyOrField(parameter, Column.Name)
Dim likeValue = Expression.Constant(value, GetType(String))
Dim condition = Expression.Call(columnProperty, GetType(String).GetMethod("Contains"), likeValue)
Dim where = Expression.Call(GetType(Queryable), "Where", New Type() {source.ElementType}, source.Expression, Expression.Lambda(condition, parameter))
Return source.Provider.CreateQuery(where)
End Function
I'm not sure you really need to worry about expression trees here. First off, we should be able to express your query as follows:
Dim targetCodes = new Int16() {32, 35, 38, 34 } ' This could be data driven as well
return from i in tblInstitutions
where i.tblInstCtgyHistories.Any(Function(ctgyHist) ctgyHist.EndDate is Nothing AndAlso
targetCodes.Contains(ctgyHist.InstCtgyCodeFK))
select i
Given that, under what case do you need the custom expression tree?

How do I return the column names of a LINQ entity

I am using LINQ to SQL queries to return data in my application. However I find it is now needful for me to return the column Names. Try as I might I have been completely unable to find out how to do this on the internet.
So if my LINQ entity table has the properties (Last_Name, First_name, Middle_Name) I need to return:
Last_name
First_Name
Middle_name
rather than the usual
Smith
John
Joe
You could certainly do it with some LINQ-To-Xml directly against the ".edmx" file or the embedded model resources in the compiled assembly.
The below query gets the field (not column) names. If you need the columns then just change the query to suit.
var edmxNS = XNamespace.Get(#"http://schemas.microsoft.com/ado/2007/06/edmx");
var schemaNS = XNamespace.Get(#"http://schemas.microsoft.com/ado/2006/04/edm");
var xd = XDocument.Load(#"{path}\Model.edmx");
var fields =
from e in xd
.Elements(edmxNS + "Edmx")
.Elements(edmxNS + "Runtime")
.Elements(edmxNS + "ConceptualModels")
.Elements(schemaNS + "Schema")
.Elements(schemaNS + "EntityType")
from p in e
.Elements(schemaNS + "Property")
select new
{
Entity = e.Attribute("Name").Value,
Member = p.Attribute("Name").Value,
Type = p.Attribute("Type").Value,
Nullable = bool.Parse(p.Attribute("Nullable").Value),
};
Lets assume you're talking about the Contact Table in the assembly named YourAssembly in a Context called MyDataContext
Using Reflection against a Table
You can use reflection to get the properties like you would any type
var properties = from property in
Type.GetType("YourAssembly.Contact").GetProperties()
select property.Name
;
foreach (var property in properties)
Console.WriteLine(property);
As shaunmartin notes this will return all properties not just Column Mapped ones. It should also be noted that this will return Public properties only. You'd need to include a BindingFlags value for the bindingAttr Parameter of GetProperties to get non-public properties
Using the Meta Model
You can use the Meta Model System.Data.Linq.Mapping to get the fields ( I added IsPersistant to only get the Column Mapped properties)
AttributeMappingSource mappping = new System.Data.Linq.Mapping.AttributeMappingSource();
var model = mappping.GetModel(typeof (MyDataContext));
var table = model.GetTable(typeof (Contact));
var qFields= from fields in table.RowType.DataMembers
where fields.IsPersistent == true
select fields;
foreach (var field in qFields)
Console.WriteLine(field.Name);
Using Reflection from a query result
If on the other hand you wanted it from a query result you can still use reflection.
MyDataContextdc = new MyDataContext();
Table<Contact> contacts = dc.GetTable<Contact>();
var q = from c in contacts
select new
{
c.FirstName,
c.LastName
};
var columns = q.First();
var properties = (from property in columns.GetType().GetProperties()
select property.Name).ToList();
I stumbled upon this answer to solve my own problem and used Conrad Frix 's answer. The question specified VB.NET though and that is what I program in. Here are Conrad's answers in VB.NET (they may not be a perfect translation, but they work):
Example 1
Dim PropertyNames1 = From Prprt In Type.GetType("LocalDB.tlbMeter").GetProperties()
Select Prprt.Name
Example 2
Dim LocalDB2 As New LocalDBDataContext
Dim bsmappping As New System.Data.Linq.Mapping.AttributeMappingSource()
Dim bsmodel = bsmappping.GetModel(LocalDB2.GetType())
Dim bstable = bsmodel.GetTable(LocalDB.tblMeters.GetType())
Dim PropertyNames2 As IQueryable(Of String) = From fields In bstable.RowType.DataMembers
Where fields.IsPersistent = True
Select fields.Member.Name 'IsPersistant to only get the Column Mapped properties
Example 3
Dim LocalDB3 As New LocalDBDataContext
Dim qMeters = From mtr In LocalDB3.tblMeters
Select mtr
Dim FirstResult As tblMeter = qMeters.First()
Dim PropertyNames3 As List(Of String) = From FN In FirstResult.GetType().GetProperties()
Select FN.Name.ToList()
To display the results:
For Each FieldName In PropertyNames1
Console.WriteLine(FieldName)
Next
For Each FieldName In PropertyNames2
Console.WriteLine(FieldName)
Next
For Each FieldName In PropertyNames3
Console.WriteLine(FieldName)
Next
Please also read Conrad's answer for notes on each method!