Contains method for comparing in multiple table - linq

I am using EF code first. Two tables.
Company table (field: CompanyName) and Tag table (TagName). Company table has a link to the Tag Table
public class Company
{
public int Id { get; set; }
public string CompanyName { get; set; }
public virtual ICollection<Tags> Tags { get; set; }
}
I want to retrieve all companies where CompanyName contains string that is been passed and also retrieve all companies that have that string as a tag
var result = from c in _db.Company
select new CompaniesVM
{
Id = c.Id,
CompanyName = c.CompanyName
};
if (!String.IsNullOrEmpty(searchString))
{
result = result.Where(s => s.CompanyName.Contains(searchString));
}
My database contains:
Company name: test1
Company name: company test
if I run the code with searchString "test" it only captures the first record. Contains method does not capture the second record. Why is that? How do I capture all records with "test" string?
Also if I have TagName "test"
Company name: ABC Inc. Tag: TagName : test
How do I look into Tags table as well and get the companies?
I am using Many-to-Many example schema below
Can I do it all in one query? maybe using lazy loading method?
much appreciated if you can point me to a similar example or sample code

Contains is case sensitive so if your data is uppercase and your searchTerm is lower case, they won't match. If you want to ignore case when searching use result.Where(s => s.CompanyName.ToLower().Contains(searchString.ToLower())). To search the Tag table as well as Company table join them
from c in _db.Company
join t in _db.Tag on c.field equals t.field
select new { Companyname = c.CompanyName, TagName = t.TagName}
where !String.IsNullOrEmpty(search) && (c.CompanyName.Contains(search) || t.TagName.COntains(search)
Update for many to many, since you have the collection on Company:
from c in _db.Company
select new {
CompanyName = c.CompanyName
}
where !string.IsNullOrEmpty(search)
&& (c.CompanyName.Contains(search) || c.Tags.Any(t => t.TagName.Contains(search))

Related

EF6 Linq Query - How to make a query when two Foreign Key Constraints are in place

For the most part EF seems to handle itself quite well, using the following query in linq, I am able to get all the related table data using FK's without having to specify the one to many relationship.
join cp in db.ClinicalPATs on s.ClinicalAssetID equals cp.ClinicalAssetID into AP
from subpat in AP.DefaultIfEmpty()
orderby s.ClinicalAssetID descending
select new ClinicalASSPATVM
{
ClinicalAssetID = s.ClinicalAssetID,
ProductName = s.ProductName,
ModelName = s.ModelName,
SupplierName = s.SupplierName,
ManufacturerName = s.ManufacturerName,
SerialNo = s.SerialNo,
PurchaseDate = s.PurchaseDate,
PoNo = s.PoNo,
Costing = s.Costing,
TeamName = s.TeamName,
StaffName = s.StaffName,
InspectionDocumnets = subpat.InspectionDocumnets ?? String.Empty,
InspectionOutcomeResult = subpat.InspectionOutcomeResult
});
the above code pulls in the relationship data from the ViewModel.
public Product ProductName { get; set; }
public InspectionOutcome InspectionOutcomeResult { get; set; }
public Model ModelName { get; set; }
public BudgetCode Code { get; set; }
public AssetType AssetTypeName { get; set; }
public Manufacturer ManufacturerName { get; set; }
public Staff StaffName { get; set; }
public Team TeamName { get; set; }
public Supplier SupplierName { get; set; }
I have a new problem which I have created for myself. I wanted to add an ID Field to the Models entity this helps me filter the data in a drop down list. I called the Field Name: ModelAssetAsignmentID And when someone adds a new ModelName from the Clinical Controller the ModelAssetAsignmentID gets a value of two.
So when i added the Field ModelAssetAsignmentID to the model "Models" i created a second FK as such:
My Original Linq Query is now broken, it no longer displays the modelname. I'm guessing this is due to the two FK Constraints.
Making the following change did not work, the InnerException is null.
var ClinicalASSPATVM = (from s in db.ClinicalAssets
where (s.ModelAssetAssignmentID.Equals(2))
join cp in db.ClinicalPATs on s.ClinicalAssetID equals cp.ClinicalAssetID into AP
from subpat in AP.DefaultIfEmpty()
orderby s.ClinicalAssetID descending
The solution is to remove the second foreign key constraint ModelAssetAssignmentID and use a viewmodel to create a value in the ModelAssetAssignmentID, thus you then do not need to modify the linq query's.

Realm Xamarin LINQ Object

What is the correct way to query Realm with LINQ where the query includes fields from other Realm objects? For example:
public class Department : RealmObject
{
[Primary Key]
public string UniqueId { get; set; }
}
public class Employee : RealmObject
{
[Primary Key]
public string Name { get; set; }
// Parent
public Department Department { get; set; }
}
Then I would expect to be able to do something like:
var employee = realm.All<Employee>().SingleOrDefault( e => e.Department.UniqueId == fooId && e.Name == fooName );
But this always returns no matches. Where() also returns no matches. However, eliminating the e.Department and searching only on employee name works fine but obviously does not scope to Department as intended.
This is with the latest Realm Xamarin 0.80.
What am I doing wrong?
Querying by nested RealmObjects attributes is not currently supported:
Just to clarify here, we don't yet support queries on related objects like this. We will in the future, but there is no timeline at the moment.
The following is also not currently supported:
var deptFilter = theRealm.ObjectForPrimaryKey<Department>("HR");
var employeesByDept = theRealm.All<Employee>().Where((Employee emp) => emp.Department == deptFilter & emp.Name == "StackOverflow");
The left-hand side of the And operator must be a direct access to a persisted property in Realm.
Unable to process '(emp.Department == value(Realm080.App+c__AnonStorey1).deptFilter)'.
You can do direct RealmObject equalities, just not in the same Linq expression, so break it down further into a sub-query.
Example of how I currently do it:
var deptFilter = theRealm.ObjectForPrimaryKey<Department>("HR");
var employeesByDept = theRealm.All<Employee>().Where((Employee emp) => emp.Department == deptFilter);
var employees = employeesByDept.Where((Employee emp) => emp.Name == "StackOverflow");
foreach (var emp in employees)
{
D.WriteLine(emp.Name);
}
Note: https://github.com/realm/realm-dotnet/issues/723

LINQ search Product Index

I have a List<Product> contains properties of Bikes (Name, ProductName, Color, List Price). I'm struggling to figure out how to write a search function using LINQ. I'd like to find a name of Bike. Any suggest will be help me some ways.
Imagine that your name is taken from a variable called nameToSearch.
This is if you want to get the Product.
string nameToSearch = "BikeName";
List<Product> list = bikes.Where(x => x.Name == nameToSearch).ToList();
I assume you have the following Product class:
public class Product
{
public String Name { get; set; }
public String ProductName { get; set; }
public String Color { get; set; }
public String List { get; set; }
public String Price { get; set; }
}
You also mentioned you have your data in a List<Product>. I will give a demo name for it:
List<Product> myProductList = GetProductList();
// Where GetProductList() will create a new List<Product> and populate it.
String bikeNameFilter = GetNameFilter();
// You can chnage this by the string you want for filtering.
You can use the following to get your data:
List<Product> myFilteredProductList = (from p in myProductList
where p.Name = bikeNameFilter
select p;
).ToList()
Obviously you can change the filter you want to use to another property of your product. Finally to get the actual name, you can loop through the list you just got:
foreach (var p in myFilteredProductList)
{
Console.WriteLine(p.ProductName);
// Use this value wherever you want.
}
Take a look at a nuget package I have created
http://www.nuget.org/packages/NinjaNye.SearchExtensions
This will enable the following (and more) which will return results where the search term appears in any of the properties specified
var result = products.Search("searchTerm", p => p.Name, p => p.ProductName);
Performing a search against all string properties can be done as follows:
var result = products.Search("searchTerm");
Alternatively, you can perform an AND search where the search term exists in a set of properties as follows:
string searchTerm = "searchTerm";
var result = products.Search(searchTerm, p => p.Name)
.Search(searchTerm, p => p.ProductName);
For more information take a look at the projects GitHub page or my blog posts
UPDATE: don't forget the using directive...
using NinjaNye.SearchExtensions

Join LINQ queries from multiple contexts

I am trying to create a ViewModel for data that I want to display in my view. The issue is, the data being displayed is spread across 2 databases and multiple tables within each. I've read that you cannot join Linq queries across multiple contexts, which makes sense, and I've also read that we can't use Code-First in EF5 to use Stored Procedures....which led me to using 3 different Linq queries and attempt to combine them into 1 ViewModel...I'm just not sure how to get there.
Here's my Linq queries:
var csdContext = new CSDContext(CustomerCode);
var masterContext = new MasterContext();
//Only returns 1 row - which is what we want.
List<Site> sites = (from s in csdContext.Sites
join sa in csdContext.SiteAddresses
on s.SiteID equals sa.SiteID
join a in csdContext.Addresses
on sa.AddressID equals a.AddressID
join spv in csdContext.SiteProductVersions
on s.SiteID equals spv.ProductVersionID
where s.SiteID == id
select s).ToList();
//List
List<States> states = (from s in masterContext.StatesTable
select s).ToList();
My ViewModel looks like this:
public class SiteDetailsViewModel
{
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string StateCode { get; set; }
public string ZipCode { get; set; }
public string OfficePhone { get; set; }
public string MobilePhone { get; set; }
public string AlternativePhone { get; set; }
public int ProductVersionID { get; set; }
}
Basically, I need the following data from these tables:
csdContext - Address
Address
Address2
City
ZipCode
csdContext - Sites
OfficePhone
MobilePhone
AlternativePhone
csdContext - SiteProductVersions
ProductVersionID
masterContext - States
StateCode
Here's how the tables are joined in SQL:
SELECT csd_a.Address, csd_a.Address2, csd_a.City, mstr_st.StateCode, csd_a.ZipCode, csd_s.OfficePhone, csd_s.MobilePhone,
csd_s.AlternativePhone, csd_spv.ProductVersionID
FROM CSD.dbo.Sites AS csd_s
INNER JOIN CSD.dbo.SiteAddress AS csd_sa ON csd_sa.SiteID = csd_s.SiteID
INNER JOIN CSD.dbo.Address AS csd_a ON csd_a.AddressID = csd_sa.AddressID
INNER JOIN CSD.dbo.SiteProductVersions AS csd_spv ON csd_s.SiteID = csd_spv.SiteID
INNER JOIN MasterDB.dbo.States AS mstr_st ON mstr_st.StateID = csd_a.StateID
I can't figure out how to merge these 3 results to create the ViewModel data for SiteDetailsViewModel. Can anyone help?
If you materialize your queries as described in OP you can use this:
var query = sites.Join(
states,
si => si.StateID,
st => st.StateID,
(si, st) => new SiteDetailsViewModel
{
Address = si.Address,
Address2 = si.Address2,
City = si.City,
StateCode = st.StateCode,
ZipCode = si.ZipCode,
OfficePhone = si.OfficePhone,
MobilePhone = si.MobilePhone,
AlternativePhone = si.AlternativePhone,
ProductVersionID = siProductVersionID
});
One possible alternate solution is to create views in DB #2 of the tables in DB #1. Then you can model/map those views in EF for DB #2. You would of course still need a context for DB #1 if you need to update any of the tables. But the benefit of this solution is that you can do all of your read access on a single context and get joins at the server instead of in memory.
So why don't you write it like this:
from ...
...
where s.SiteID == id
select new SiteDetailsViewModel()
{
Address = sa.Address,
Address2 = as.Address2,
..
}

Linq2Sql relationships and WCF serialization problem

here is my scenario
i got
Table1
id
name
Table2
id
family
fid
with one to many relationship set between Table1. id and Table2.fid
now here is my WCF service Code
[OperationContract]
public List<Table1> GetCustomers(string numberToFetch)
{
using (DataClassesDataContext context = new DataClassesDataContext())
{
return context.Table1s.Take(int.Parse(numberToFetch)).ToList( );
}
}
and my ASPX page Code
<body xmlns:sys="javascript:Sys"
xmlns:dataview="javascript:Sys.UI.DataView">
<div id="CustomerView"
class="sys-template"
sys:attach="dataview"
dataview:autofetch="true"
dataview:dataprovider="Service2.svc"
dataview:fetchParameters="{{ {numberToFetch: 2} }}"
dataview:fetchoperation="GetCustomers">
<ul>
<li>{{family}}</li>
</ul>
</div>
though i set serialization mode to Unidirectional in Linq2Sql designer i am not able to get the family value and all what i get is this in firebug
{"d":[{"__type":"Table1:#","id":1,"name":"asd"},{"__type":"Table1:#","id":2,"name":"wewe"}]}
any help would be totally appreciated
Well, the point is: your method GetCustomers only ever selects from Table1 - I don't see any reference at all to Table2, where your Family column is located......
You need to check into Linq-to-SQL JOIN's and how to fetch data from a joined table into your result set.
Something along the lines of:
[DataContract]
class JoinedResult
{
[DataMember]
public int Table1ID { get; set; }
[DataMember]
public string Table1Name { get; set; }
[DataMember]
public string Table2Family { get; set; }
}
[OperationContract]
public List<JoinedResult> GetCustomers(int numberToFetch)
{
using (DataClassesDataContext context = new DataClassesDataContext())
{
var q = from t1 in context.Table1
join t2 in context.Table2 on t1.id = t2.fid
select new JoinedResult
{ Table1ID = t1.ID,
Table1Name = t1.Name,
Table2Family = t2.Family };
return q.Take(numberToFetch).ToList();
}
}
and btw: you should really make numberToFetch an INT parameter! Let the caller make the conversion......
UPDATE: if you don't want to explicitly include the second table to be queried, you could instead add a DataLoadOption to your context:
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Table1>(t => t.Table2);
context.LoadOptions = dlo;
In that case, you tell LINQ to always include all elements from Table2 when it loads anything from Table1 - that should work, too.

Resources