Linq to Entities convert one entity to similar - vb.net

I have an Entity model with entities of Person and LogPerson. they are identical except that LogPerson has 2 additional fields (LogPersonID, CreateDate). How can I cast a LogPerson into a Person so that the VB.NET code that follows my Linq code doesn't have to try to work with both possible types?
For example:
dim p as person
If useLog then
p = From a In LogPerson Where ID = x
Else
p = From a In Person Where ID = x
End If
textbox1.text = p.firstname

There aren't any ways out-of-the box. The easiest way without third party tools/libraries is to use the Select method and map the properties manually, like so:
IEnumerable<Person> people = ...;
IEnumerable<LogPerson> logPeople = people.Select(p => new LogPerson {
Name = p.Name,
Age = p.Age,
...
});
Of course, this is tedious, so if you have a large number of fields or a number of places you have to perform this kind of operation, you might want to look into an auto mapping library, such as AutoMapper.

I am WRITING THE SOLUTION IN C#....
person p;
if(uselog)
{
var per = from pobj in LogPerson
where pobj.ID= x
select new person{
firstname = pobj.firstname,
lastname = pobj.lastname,
};
}else
{
var per = from pobj in Person
where pobj.ID= x
select new person{
firstname = pobj.firstname,
lastname = pobj.lastname,
};
}
p = per.first();
}
textbox1.text = p.firstname

Related

MapKit: How to retrieve apartment number from the return value of MKLocalSearchResponse

I searched thoroughly online but couldn't find any discussion about this:
The MKLocalSearchResponse object returned from a MapKit search is a collection of MKMapItem, which has the information of search results, e.g. City, state, country.
A single MKMapItem looks like this(from Xcode quick look of the object):
"Name: ADVANCED SOLUTIONS ADDICTION MANAGEMENT CurrentLocation: 0 Place: <GEOPlace: 0x9b2db90> {
address = {
formattedAddressLine = (
\"205 W Crestway Ave\",
\"Unit 200\",
\"Derby, KS 67037-1850\",
\"United States\"
);
structuredAddress = {
administrativeArea = Kansas;
administrativeAreaCode = KS;
country = \"United States\";
countryCode = US;
dependentLocality = (
Derby,
Rockford
);
fullThoroughfare = \"205 W Crestway Ave\";
geoId = (
);
locality = Derby;
postCode = 67037;
postCodeExtension = 1850;
postCodeFull = \"67037-1850\";
subAdministrativeArea = Sedgwick;
subLocality = Rockford;
subPremise = (
{
name = 200;
type = 0;
}
);
subThoroughfare = 205;
thoroughfare = \"W Crestway Ave\";
};
};
}"
I was able to retrieve all the information I needed, except the Apartment number. It's contained in the "subPremise" part, which I don't know how to retrieve.
You may suggest me to retrieve it from the "formattedAddressLines", which I have access to, but for some results, that property is empty, so I cannot rely on it.
I've also tried the "addressDictionary" property, it has all the necessary information except apartment number, which is very unthoughtful to me.
mapItem.placemark.subThoroughfare. Note that it may be empty

How do I map lists of nested objects with Dapper

I'm currently using Entity Framework for my db access but want to have a look at Dapper. I have classes like this:
public class Course{
public string Title{get;set;}
public IList<Location> Locations {get;set;}
...
}
public class Location{
public string Name {get;set;}
...
}
So one course can be taught at several locations. Entity Framework does the mapping for me so my Course object is populated with a list of locations. How would I go about this with Dapper, is it even possible or do I have to do it in several query steps?
Alternatively, you can use one query with a lookup:
var lookup = new Dictionary<int, Course>();
conn.Query<Course, Location, Course>(#"
SELECT c.*, l.*
FROM Course c
INNER JOIN Location l ON c.LocationId = l.Id
", (c, l) => {
Course course;
if (!lookup.TryGetValue(c.Id, out course))
lookup.Add(c.Id, course = c);
if (course.Locations == null)
course.Locations = new List<Location>();
course.Locations.Add(l); /* Add locations to course */
return course;
}).AsQueryable();
var resultList = lookup.Values;
See here https://www.tritac.com/blog/dappernet-by-example/
Dapper is not a full blown ORM it does not handle magic generation of queries and such.
For your particular example the following would probably work:
Grab the courses:
var courses = cnn.Query<Course>("select * from Courses where Category = 1 Order by CreationDate");
Grab the relevant mapping:
var mappings = cnn.Query<CourseLocation>(
"select * from CourseLocations where CourseId in #Ids",
new {Ids = courses.Select(c => c.Id).Distinct()});
Grab the relevant locations
var locations = cnn.Query<Location>(
"select * from Locations where Id in #Ids",
new {Ids = mappings.Select(m => m.LocationId).Distinct()}
);
Map it all up
Leaving this to the reader, you create a few maps and iterate through your courses populating with the locations.
Caveat the in trick will work if you have less than 2100 lookups (Sql Server), if you have more you probably want to amend the query to select * from CourseLocations where CourseId in (select Id from Courses ... ) if that is the case you may as well yank all the results in one go using QueryMultiple
No need for lookup Dictionary
var coursesWithLocations =
conn.Query<Course, Location, Course>(#"
SELECT c.*, l.*
FROM Course c
INNER JOIN Location l ON c.LocationId = l.Id
", (course, location) => {
course.Locations = course.Locations ?? new List<Location>();
course.Locations.Add(location);
return course;
}).AsQueryable();
I know I'm really late to this, but there is another option. You can use QueryMultiple here. Something like this:
var results = cnn.QueryMultiple(#"
SELECT *
FROM Courses
WHERE Category = 1
ORDER BY CreationDate
;
SELECT A.*
,B.CourseId
FROM Locations A
INNER JOIN CourseLocations B
ON A.LocationId = B.LocationId
INNER JOIN Course C
ON B.CourseId = B.CourseId
AND C.Category = 1
");
var courses = results.Read<Course>();
var locations = results.Read<Location>(); //(Location will have that extra CourseId on it for the next part)
foreach (var course in courses) {
course.Locations = locations.Where(a => a.CourseId == course.CourseId).ToList();
}
Sorry to be late to the party (like always). For me, it's easier to use a Dictionary, like Jeroen K did, in terms of performance and readability. Also, to avoid header multiplication across locations, I use Distinct() to remove potential dups:
string query = #"SELECT c.*, l.*
FROM Course c
INNER JOIN Location l ON c.LocationId = l.Id";
using (SqlConnection conn = DB.getConnection())
{
conn.Open();
var courseDictionary = new Dictionary<Guid, Course>();
var list = conn.Query<Course, Location, Course>(
query,
(course, location) =>
{
if (!courseDictionary.TryGetValue(course.Id, out Course courseEntry))
{
courseEntry = course;
courseEntry.Locations = courseEntry.Locations ?? new List<Location>();
courseDictionary.Add(courseEntry.Id, courseEntry);
}
courseEntry.Locations.Add(location);
return courseEntry;
},
splitOn: "Id")
.Distinct()
.ToList();
return list;
}
Something is missing. If you do not specify each field from Locations in the SQL query, the object Location cannot be filled. Take a look:
var lookup = new Dictionary<int, Course>()
conn.Query<Course, Location, Course>(#"
SELECT c.*, l.Name, l.otherField, l.secondField
FROM Course c
INNER JOIN Location l ON c.LocationId = l.Id
", (c, l) => {
Course course;
if (!lookup.TryGetValue(c.Id, out course)) {
lookup.Add(c.Id, course = c);
}
if (course.Locations == null)
course.Locations = new List<Location>();
course.Locations.Add(a);
return course;
},
).AsQueryable();
var resultList = lookup.Values;
Using l.* in the query, I had the list of locations but without data.
Not sure if anybody needs it, but I have dynamic version of it without Model for quick & flexible coding.
var lookup = new Dictionary<int, dynamic>();
conn.Query<dynamic, dynamic, dynamic>(#"
SELECT A.*, B.*
FROM Client A
INNER JOIN Instance B ON A.ClientID = B.ClientID
", (A, B) => {
// If dict has no key, allocate new obj
// with another level of array
if (!lookup.ContainsKey(A.ClientID)) {
lookup[A.ClientID] = new {
ClientID = A.ClientID,
ClientName = A.Name,
Instances = new List<dynamic>()
};
}
// Add each instance
lookup[A.ClientID].Instances.Add(new {
InstanceName = B.Name,
BaseURL = B.BaseURL,
WebAppPath = B.WebAppPath
});
return lookup[A.ClientID];
}, splitOn: "ClientID,InstanceID").AsQueryable();
var resultList = lookup.Values;
return resultList;
There is another approach using the JSON result. Even though the accepted answer and others are well explained, I just thought about an another approach to get the result.
Create a stored procedure or a select qry to return the result in json format. then Deserialize the the result object to required class format. please go through the sample code.
using (var db = connection.OpenConnection())
{
var results = await db.QueryAsync("your_sp_name",..);
var result = results.FirstOrDefault();
string Json = result?.your_result_json_row;
if (!string.IsNullOrEmpty(Json))
{
List<Course> Courses= JsonConvert.DeserializeObject<List<Course>>(Json);
}
//map to your custom class and dto then return the result
}
This is an another thought process. Please review the same.

Entity Framework: Update entity or add if it doesn't exist

I have a scenario where I have to update an entity if it exists or add a new one if it doesn't.
I would like to execute a single method for this (it would be great if it were a single trip to the server).
Is there something like that in EF?
Right now my code looks like this:
var entity = db.Entities.FirstOrDefault(e => e.Id == myId);
if (entity == null)
{
entity = db.Entities.CreateObject();
entity.Id = myId;
}
entity.Value = "my modified value";
db.SaveChanges();
But I would like to avoid the first query, something like this:
var entity = new Entity();
entity.Id = myId;
entity.Value = "my modified value";
db.AddOrAttach(entity);
db.SaveChanges();
Is there anything similar? or do I have to perform the first query no matter what?
Thanks
You have to perform the first query no matter what, unfortunately.
One option would be to write a stored procedure that performs a T-SQL MERGE then map it to a function import, though that would require that you pass the scalar values of the entity as parameters (and support for navigation properties would be done), but it would accomplish what you're after.
I ran some quick test code for editing in MVC 3 with EF 4 and it seems to work for edit with following code:
using (var context = new TestStackOverFlowEntities())
{
Person p = new Person();
p.Id = long.Parse(collection["Id"]);
p.FirstName = collection["FirstName"];
p.LastName = collection["LastName"];
context.People.Attach(p);
context.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Modified);
context.SaveChanges();
return RedirectToAction("Index");
}
Edit: I checked with creating new object too, you need to change this
context.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Added);
when Id == 0 //ie new object.
Quick and dirty code to add new is this:
using (var context = new TestStackOverFlowEntities())
{
Person p = new Person();
p.Id = 0;
p.FirstName = collection["FirstName"];
p.LastName = collection["LastName"];
context.People.Attach(p);
context.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Added);
context.SaveChanges();
return RedirectToAction("Index");
}
If you are just trying to limit code to clarify your controllers:
db.Attach(model);
db.SaveChanges(model);
Will update if the Entity Key exists, and create if it does not.

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!

nhibernate hql with named parameter

I have implemented a search function using Castel Active Record. I thought the code is simple enough but I kept getting
NHibernate.QueryParameterException : could not locate named parameter [searchKeyWords]
errors. Can someone tell me what went wrong? Thanks a million.
public List<Seller> GetSellersWithEmail(string searchKeyWords)
{
if (string.IsNullOrEmpty(searchKeyWords))
{
return new List<Seller>();
}
string hql = #"select distinct s
from Seller s
where s.Deleted = false
and ( s.Email like '%:searchKeyWords%')";
SimpleQuery<Seller> q = new SimpleQuery<Seller>(hql);
q.SetParameter("searchKeyWords", searchKeyWords);
return q.Execute().ToList();
}
Why do not u pass the % character with parameter?
string hql = #"select distinct s
from Seller s
where s.Deleted = false
and ( s.Email like :searchKeyWords)";
SimpleQuery<Seller> q = new SimpleQuery<Seller>(hql);
q.SetParameter("searchKeyWords", "%"+searchKeyWords+"%");
return q.Execute().ToList();