Always Encrypted Operand Clash In Query - c#

I've recently started to use Always Encrypted with SQL Server 2016 to encrypt sensitive information.
For the most part, everything has been plain sailing with regards to seamless transition.
One thing has cropped up though, the following error -
Operand type clash: nvarchar(255) encrypted with (encryption_type =
'RANDOMIZED', encryption_algorithm_name =
'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name =
'CEK_AutoK2', column_encryption_key_database_name = 'hrsys') is
incompatible with nvarchar Statement(s) could not be prepared.
The method that is throwing this exception is the following -
public ActionResult GetStaffList(string term)
{
var staffs = from e in db.Staffs
where e.FirstName.Contains(term) || e.LastName.Contains(term)
&& e.EmploymentStatus == "Active"
select new
{
label = e.FirstName + " " + e.LastName,
id = e.Id
};
return (Json(staffs, JsonRequestBehavior.AllowGet));
}
But, if I modify the method, to this-
public ActionResult GetStaffList(string term)
{
var staffSearch= db.Staffs
.ToList()
.Where(e => e.FirstName.Contains(term) || e.LastName.Contains(term))
.Where(e => e.EmploymentStatus == "Active");
var staffs = from e in staffSearch
select new
{
label = e.FirstName + " " + e.LastName,
id = e.Id
};
return (Json(staffs, JsonRequestBehavior.AllowGet));
}
It doesn't throw an error.
Is there anyway of consolidating the two 'query' variables to a single one, making sure that the data is returned as JSON with the following block -
select new
{
label = e.FirstName + " " + e.LastName,
id = e.Id
}
Also what I cant get my head around is that when querying with 'from e .....' it throws an error, but when querying with 'db.Staff ...' it doesn't.

Related

Why Linq to Entities cannot convert this call to SQL?

var providerTypes = from provider_types in dbContext.vw_LookUpProviderType
select new vw_LookUpProviderType
{
ApplicationUser = provider_types.ApplicationUser,
ProviderTypeId = provider_types.ProviderTypeId,
Type = provider_types.Type
};
var query =
from providerCoi in dbContext.Provider_COI
where providerCoi.COIProviderId == message.ProviderId
join providerDetail in dbContext.ProviderDetail
on providerCoi.ProviderId equals providerDetail.ProviderId
into providerDetails
from providerDetail in providerDetails.DefaultIfEmpty()
select new Result
{
PhysicianAdvisorId = providerCoi.ProviderId,
HasConflictOfInterest = providerCoi.COIFlag == true,
PhysicianAdvisorName = providerDetail.FirstName + " " + providerDetail.MiddleName + " " + providerDetail.LastName,
ProviderType = providerTypes
.Where(providerType => providerDetail.ProviderTypeIds.Contains(providerType.ProviderTypeId.ToString()))
.Select(providerType => providerType.Type)
.ToArray<string>()
.Aggregate((current, next) => current +", " + current)
};
I have selected the providerTypes. There is table providerDetails, and and there there is field providerTypeIds - this is can't be changed. For example providerTypes: [1: 'Type 1', 2: 'Type 2', 3: 'Type 4'] and providerTypeIds: '1,2,':
Select from providerTypes that types that can be found in providerIdsString
providerTypes.Where(providerType => providerDetail.ProviderTypeIds.Contains(providerType.ToString())) // => [1: 'Type 1', 2: 'Type 2']
Than select on string representations: .Select(providerType => providerType.Type) // => ['Type 1', 'Type 2']
And finally transform all of them into string of types separated by comma:
.ToArray<string>()
.Aggregate((current, next) => current +", " + current) // => 'Type 1, Type 2
And this is throws an exception
LINQ to Entities does not recognize the method 'System.String
Aggregate[String](System.Collections.Generic.IEnumerable1[System.String],
System.Func3[System.String,System.String,System.String])'
So, as was mentioned in comments, Aggregate function is not supported in Linq to Entities, see ref for more details: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-linq-methods-linq-to-entities#aggregate-methods
Unfortunetely simple toList, didn't help me, I don't know the certain reason, but maybe it because of use field for search - providerTypes, maybe toList on the providerTypes could help, but I've used another workaround - select physicianIds string, and then manualy transform it. See code below.
//select provider types lookup, from there can map id with it text meaning, f.e.[{providerTypeId: 1, type: 'Value 1' },{providerTypeId: 2, type: 'Value 2' }]
var providerTypes = exUrDataContext.vw_LookUpProviderType.ToList();
//select physicianCois with unmodified providerTypeIds(f.e '1,2,')
var physicianCois =
await (from providerCoi in dbContext.Provider_COI
where providerCoi.COIProviderId == message.PhysicianId
join providerDetail in exUrDataContext.vw_ProviderDetail
on providerCoi.ProviderId equals providerDetail.ProviderId
into providerDetails
from providerDetail in providerDetails.DefaultIfEmpty()
select new Result
{
PhysicianAdvisorId = providerCoi.ProviderId,
HasConflictOfInterest = providerCoi.COIFlag == true,
PhysicianAdvisorName = providerDetail.FirstName + " " + providerDetail.MiddleName + " " + providerDetail.LastName,
ProviderType = providerDetail.ProviderTypeIds
}).ToListAsync();
//map string with ids to string from text values, f.e. '1,2' => 'Value 1, Value 2'
foreach (var physicianCoi in physicianCois)
{
string physicianProviderNames = "";
foreach (var providerKey in physicianCoi.ProviderType.Split(new char[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries))
{
if (!physicianProviderNames.Equals(""))
{
physicianProviderNames += ", ";
}
physicianProviderNames += providerTypes.Where(providerType => providerType.ProviderTypeId == int.Parse(providerKey)).FirstOrDefault().Type;
}
physicianCoi.ProviderType = physicianProviderNames;
}

LINQ Query not pulling all records needed

I am having some trouble with a LINQ query.
This query creates a list of new objects based on entries from a repository.
Here is the original query:
var accounts = (from a in entityRepository.Queryable<Account>()
from l in a.ExternalLogins
select new
{
a.ID,
FullName = a.FirstName + " " + a.LastName,
Status = a.Status == AccountStatus.Closed ? Enums.Status.Inactive : Enums.Status.Active,
Login = new
{
ConnectionID = l.Connection.ID,
l.Connection.ConnectionType,
l.Identity
},
a.AdminAccess,
a.Username,
a.Email
}).ToList();
My issue is that not all a have an a.ExternalLogins. The query is not pulling those accounts because of the additional from statement from l in a.ExternalLogins. I tried modifying the query to:
var accounts = (from a in entityRepository.Queryable<Account>()
select new
{
a.ID,
FullName = a.FirstName + " " + a.LastName,
Status = a.Status == AccountStatus.Closed ? Enums.Status.Inactive : Enums.Status.Active,
Login = (from l in a.ExternalLogins
select new
{
ConnectionID = l.Connection.ID,
l.Connection.ConnectionType,
l.Identity
}),
a.AdminAccess,
a.Username,
a.Email
}).ToList();
But I am getting a 'System.Reflection.AmbiguousMatchException' exception.
From looking up that exception, I am guessing that the reason is because both Account and Connection have the field ID.
Am I headed in the right direction with this? Do I chase down this exception, or is my query not correct?
I apologize if this is trivial; I'm new to LINQ queries, and my google skills have failed me at this point!
To do a left outer join in Linq, add a DefaultIfEmpty() call and check for null in the results:
var accounts = (from a in entityRepository.Queryable<Account>()
from l in a.ExternalLogins.DefaultIfEmpty()
select new
{
a.ID,
FullName = a.FirstName + " " + a.LastName,
Status = a.Status == AccountStatus.Closed ? Enums.Status.Inactive : Enums.Status.Active,
Login = (l == null) ? null : new
{
ConnectionID = l.Connection.ID,
l.Connection.ConnectionType,
l.Identity
},
a.AdminAccess,
a.Username,
a.Email
}).ToList();

LINQ to Entities does not recognize the method 'System.String GetMonthName(Int32)' method

What am I doing wrong?
FYI The repository method GetResearchArticles() returns an IQueryable.
var grouped = (from p in _researchArticleRepository.GetResearchArticles()
group p by new { month = p.DatePublished.Month, year = p.DatePublished.Year } into d
select new
{
dt = d.Key.month + "-" + d.Key.year,
dtByMonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(d.Key.month) + " " + d.Key.year
}//count = d.Count() }
)
.OrderByDescending(g => g.dt);
return grouped.ToDictionary(item => item.dt, item => item.dtByMonthName);
It is probably trying to convert that statement to a SQL expression, which it cannot do. Instead of trying to do that on the database, you should make that call on data that has already been retrieved from the database.
Basically, you need to run .ToList() or something to force the fetching of the data, and then make a call to GetMonthName()
since your not doing any filtering this should work but your pulling out all research articles into memory because SQL doesnt understand how to get month
var grouped = (from p in _researchArticleRepository.GetResearchArticles().ToList()
group p by new { month = p.DatePublished.Month, year = p.DatePublished.Year } into d
select new
{
dt = d.Key.month + "-" + d.Key.year,
dtByMonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(d.Key.month) + " " + d.Key.year
}//count = d.Count() }
)
.OrderByDescending(g => g.dt);
return grouped.ToDictionary(item => item.dt, item => item.dtByMonthName);

Attempted Left Join in Query Syntax and Lambda results in "The method or operation is not implemented."

I've attempted to write this query two different ways, and no matter how I write it, I can't get the join to pan out. It just keeps tossing "The method or operation is not implemented." at me. What I'm trying to do is, in SQL, simple: Obtain a list of items from table A (below - Customer) where there is no corresponding listing in table B (below - SalesReps).
Attempted Lamda:
var customers =
_sms.CurrentSession.Query<customer>()
.GroupJoin(_sms.CurrentSession.Query<salesReps>(),
c => c.Id,
sr => sr.CustomerId,
(x, y) => new {c = x, sr = y})
.SelectMany(xy => xy.sr.DefaultIfEmpty(),
(x, y) => new {c = x.c, sr = y})
.Where(data => data.sr.SalesRepId == null)
.Select(data => new CustomerDTO
{
Id = data.c.Id,
FullName = data.c.FirstName + " " + data.c.LastName,
FirstName = data.c.FirstName,
LastName = data.c.LastName
});
var custList = customers .ToList();
Attempted Query Syntax:
var customers = from c in _sms.CurrentSession.Query<customer>()
join sr in _sms.CurrentSession.Query<salesReps>()
on c.Id equals sr.CustomerId
into joinedData
from jd in joinedData.DefaultIfEmpty()
where c.IsEmployee == false
&& c.CustomerOptions.Company.Id == companyGuid
&& jd.SalesRepId == null
select
new CustomerDTO
{
Id = c.Id,
FullName = c.FirstName + " " + c.LastName,
FirstName = c.FirstName,
LastName = c.LastName
};
var custList = customers .ToList();
I get the impression that the issue is on the check for null sales reps, but I'm not sure.

Multiple Left Join LINQ-to-entities

I have 3 tables:
Dealerships
------------
ID, Name, Website
Locations
------------
ID, DealershipID, Address, Ect.
Contacts
------------
ID, LocationID, Name, Ect.
So the relationship shows that we have dealerships who have multiple locations (Example: Weed Chevrolet of PA, Weed Chevrolet of NJ) and then each location has its own contacts (Example: Managers of PA location, Managers of NJ location). I need to join the 3 tables together. This is what I have:
var results = from d in entities.dealerships
join l in entities.locations on d.ID equals l.DealershipID
join c in entities.contacts on l.ID equals c.LocationID
select new
{
Name = d.Name,
Website = d.Website,
Address = l.Address + ", " + l.City + ", " + l.State + " " + l.Zip,
Contact = c.FirstName + " " + c.LastName,
WorkPhone = c.WorkPhone,
CellPhone = c.CellPhone,
HomePhone = c.HomePhone,
Email = c.Email,
AltEmail = c.AltEmail,
Sells = l.Sells
}
When I attempt to bind results to a BindingSource and then to a DataGridView I receive the following error:
Unable to cast the type 'System.Nullable`1' to type 'System.Object'.
LINQ to Entities only supports casting Entity Data Model primitive types.
What can it be? I am new to JOIN statements in LINQ so I am sure I am doing something wrong.
EDIT: There is data in the database so the results shouldn't be null, just to clarify
You were close but I discovered that you have to convert it from LINQ-To-Entities to LINQ-To-Objects. First I had to cast the entities using AsEnumerable() then use ToList(). This made it so I could use functions like ToString() and String.Format(). Thanks for leading me in the right direction. Here is the final code:
var query = from d in entities.dealerships
from l in entities.locations.Where(loc => loc.DealershipID == d.ID).DefaultIfEmpty()
from c in entities.contacts.Where(cont => cont.LocationID == l.ID).DefaultIfEmpty()
where d.Keywords.Contains(keywords) || l.Keywords.Contains(keywords) || l.Sells.Contains(keywords) || c.Keywords.Contains(keywords)
select new
{
Dealership = d,
Location = l,
Contact = c
};
var results = (from r in query.AsEnumerable()
select new
{
Name = r.Dealership.Name,
Website = r.Dealership.Website,
Contact = r.Contact.FirstName + " " + r.Contact.LastName,
Address = r.Location.Address + ", " + r.Location.City + ", " + r.Location.State + " " + r.Location.Zip,
WorkPhone = r.Contact.WorkPhone,
CellPhone = r.Contact.CellPhone,
Fax = r.Contact.Fax,
Email = r.Contact.Email,
AltEmail = r.Contact.AltEmail,
Sells = r.Location.Sells
}).ToList();
bindingSource.DataSource = results;
Since your results is IQueryable, EF will try to cast on the data store side and it won't work because cast only works with scalar types. You should call ToList() on the results like this:
var results = (from d in entities.dealerships
join l in entities.locations on d.ID equals l.DealershipID
join c in entities.contacts on l.ID equals c.LocationID
select new
{
Name = d.Name,
Website = d.Website,
Address = l.Address + ", " + l.City + ", " + l.State + " " + l.Zip,
Contact = c.FirstName + " " + c.LastName,
WorkPhone = c.WorkPhone,
CellPhone = c.CellPhone,
HomePhone = c.HomePhone,
Email = c.Email,
AltEmail = c.AltEmail,
Sells = l.Sells
}).ToList();
var EmplistDriver = (from a in data
join b in db.DesignationDetails on a.DesignationID equals b.DesignationDetailID into EmployeeBonus
from b in dataBonus.DefaultIfEmpty()
join x in db.EmployeeCommission on a.EmployeeDetailID equals x.EmployeeDetailID into EmployeeCommission
from x in dataComm.DefaultIfEmpty()
join c in db.EmployeeAdvance on a.EmployeeDetailID equals c.FKEAEmployeeID
join d in db.EmployeeAllowance on a.EmployeeAllowanceID equals d.EmployeeAllowanceID
join e in dataAtt on a.EmployeeDetailID equals e.EmployeeDetailID
join f in dataDri on a.EmployeeDetailID equals f.EmployeeDetailID
join h in db.ProjectAllocation on f.FKAllocationID equals h.PKAllocationID
join i in db.ProjectDetails on h.FKProjectDetailID equals i.ProjectDetailID
where a.IsActive == true && c.EAIsActive == true && d.IsActive == true && e.EAIsActive == true && h.IsActivity == true
select new
{
c.BalanceAmount,
c.BalanceDue,
d.FoodAllowance,
i.DriverBasicSalary,
d.OtherAllowance,
d.AccommodationAllowance,
e.EABasicWorktime,
BonusAmount = (b.BonusAmount == null ? 0 : b.BonusAmount),
CommissionAmount = (x.CommissionAmount == null ? 0 : x.CommissionAmount),
TotalOverTime,
TotalHr
}).FirstOrDefault();

Categories

Resources