NHibernate one-to-one mapping with unique foreign key - linq

I'm seeing some unexpected query behavior with a one-to-one mapping where the "child" record is possibly null. Nhibernate seems to generate inner joins when it seems like a left join would be more appropriate. Given the following schema:
CREATE TABLE [dbo].[Customer](
[CustomerId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NOT NULL,
[AccountNumber] [int] NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[CustomerId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Employee](
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NOT NULL,
[Title] [varchar](50) NOT NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
(
[EmployeeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Person](
[PersonId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
(
[PersonId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[Customer] WITH CHECK ADD CONSTRAINT [FK_Customer_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([PersonId])
GO
ALTER TABLE [dbo].[Customer] CHECK CONSTRAINT [FK_Customer_Person]
GO
ALTER TABLE [dbo].[Employee] WITH CHECK ADD CONSTRAINT [FK_Employee_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([PersonId])
GO
ALTER TABLE [dbo].[Employee] CHECK CONSTRAINT [FK_Employee_Person]
GO
And the following classes:
namespace OneToOneMapping.Model
{
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Customer Customer { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
public virtual System.Int32 Id { get; set; }
public virtual Person Person { get; set; }
public virtual string Title { get; set; }
}
public class Customer
{
public virtual System.Int32 Id { get; set; }
public virtual Person Person { get; set; }
public virtual int AccountNumber { get; set; }
}
}
And mappings:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="OneToOneMapping"
namespace="OneToOneMapping.Model">
<class name="Person" table="Person" lazy="true" >
<id name="Id" column="PersonId">
<generator class="identity"/>
</id>
<one-to-one name="Customer" cascade="all-delete-orphan" property-ref="Person" class="OneToOneMapping.Model.Customer" />
<one-to-one name="Employee" cascade="all-delete-orphan" property-ref="Person" class="OneToOneMapping.Model.Employee" />
<property name="Name"/>
</class>
<class name="OneToOneMapping.Model.Customer, OneToOneMapping" table="Customer">
<id name="Id" column="CustomerId">
<generator class="identity"/>
</id>
<property name="AccountNumber"/>
<many-to-one name="Person" class="Person" column="PersonId" unique="true" cascade="save-update"/>
</class>
<class name="OneToOneMapping.Model.Employee, OneToOneMapping" table="Employee" lazy="true" mutable="true">
<id name="Id" column="EmployeeId">
<generator class="identity"/>
</id>
<property name="Title"/>
<many-to-one name="Person" class="Person" column="PersonId" unique="true" cascade="save-update"/>
</class>
</hibernate-mapping>
I am unable to create a linq query where I can return a projection indicating whether a Customer is also an Employee (or vice versa). Running something like the following statement:
var t = Session.Query<Customer>().Select(c => new { AccountNumber = c.AccountNumber, Name= c.Person.Name, IsEmployee = c.Person.Employee.Id != null }).ToList();
Generates the following SQL (note the "where" clause prevents any Customer records that don't have also have an associated Employee record from returning at all):
SELECT customer0_.AccountNumber AS col_0_0_
,person1_.NAME AS col_1_0_
,employee2_.EmployeeId AS col_2_0_
FROM Customer customer0_
LEFT JOIN Person person1_ ON customer0_.PersonId = person1_.PersonId
,Employee employee2_
WHERE person1_.PersonId = employee2_.PersonId
I'd expect it to generate something like the following to just return a null EmployeeId when the record does not exist:
SELECT customer0_.AccountNumber AS col_0_0_
,person1_.NAME AS col_1_0_
,employee2_.EmployeeId AS col_2_0_
FROM Customer customer0_
LEFT JOIN Person person1_ ON customer0_.PersonId = person1_.PersonId
Left Join Employee employee2_ on person1_.PersonId = employee2_.PersonId
Am I missing something or is this a known issue with the "one-to-one" mapping?

We've identified a different query method using subqueries in the projections that seems to work. I believe the underlying issue is related to the open issue here: https://nhibernate.jira.com/browse/NH-3117?jql=text%20~%20%22one%20to%20one%22. It appears that the NHibernate linq provider doesn't properly handle one-to-one mappings where the referencing item(s) possibly doesn't exist.
The workaround:
var t = Session.Query<Customer>()
.Select(c => new {
AccountNumber = c.AccountNumber,
Name= c.Person.Name,
IsEmployee = Session.Query<Employee>().Any(e => e.Id == c.Person.Id)
}).ToList();
Generates the following SQL:
SELECT customer0_.AccountNumber AS col_0_0_
,person1_.NAME AS col_1_0_
,CASE
WHEN EXISTS (
SELECT employee2_.EmployeeId
FROM Employee employee2_
WHERE employee2_.EmployeeId = customer0_.PersonId
)
THEN 1
ELSE 0
END AS col_2_0_
FROM Customer customer0_
LEFT JOIN Person person1_ ON customer0_.PersonId = person1_.PersonId

Related

nHibernate join and take one record

I'm doing the below join, there are many bookingActions records, but I want there to only be one BookingAction record per booking record. I want the BookingAction record that has the highest primary key value.
How would I do this?
var bookingLocationsQuery = (
from
booking in session.Query<Booking>()
join
bookingActions in session.Query<BookingAction>() on booking.Id equals bookingActions.bookingId
where
(booking.bookingAdminID == userId)
select new { booking, bookingActions }
);
A couple of suggestions. First, you should be leveraging NHibernate's many-to-one to do the join for you instead of doing it manually. It looks like you currently have something like this...
public class BookingAction
{
// ... other properties ...
public virtual int bookingId { get; set; }
}
<class name="BookingAction">
<!-- ... other properties ... -->
<property name="bookingId" />
</class>
Don't do that. Instead, you should have:
public class BookingAction
{
// ... other properties ...
public virtual Booking Booking { get; set; }
}
<class name="BookingAction">
<!-- ... other properties ... -->
<many-to-one name="Booking" column="bookingId" />
</class>
Similar advice for Booking.bookingAdminID. It should be a many-to-one to User, not just a simple property.
Second, after you make those changes, you should be able to accomplish your goal with a query like this:
var subquery = session.Query<BookingAction>()
.Where(a => a.Booking.Admin.Id == userId)
.GroupBy(a => a.Booking.Id)
.Select(g => g.Max(a => a.Id));
var bookingActions = session.Query<BookingAction>()
.Fetch(a => a.Booking)
.Where(a => subquery.Contains(a.Id));
Sorry about switching it to the chained extension method syntax - that's easier for me to work with. It's exactly equivalent to the from ... select syntax in execution.
Try using the Max() method, for sample:
var bookingLocation = session.Query<Booking>()
.Where(booking => booking.bookingAdminID == userId)
.Max(x => booking.bookingAdminID);

How do I work around the N+1 issue with one-to-one mapping in NHibernate?

I have a Task entity which has a preceding and following task:
namespace OneToOneIssue.Domain
{
public class Task
{
public virtual Guid Id { get; set; }
public virtual string Description { get; set; }
public virtual Task FollowingTask { get; set; }
public virtual Task PrecedingTask { get; set; }
}
}
The database table looks like this:
CREATE TABLE [dbo].[Task](
[Id] uniqueidentifier NOT NULL,
[Description] nvarchar(100) NULL,
[FollowingTaskId] uniqueidentifier NULL
CONSTRAINT [PK_Task] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('30efbfda-f3b5-42fb-906e-098fb32be79d', 'Task 1', 'f7367187-406d-47db-931e-b9e4fa8a4774')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('f7367187-406d-47db-931e-b9e4fa8a4774', 'Task 2', '42c25da5-7c04-4adc-a9c2-6bf8a9ff5c89')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('42c25da5-7c04-4adc-a9c2-6bf8a9ff5c89', 'Task 3', NULL)
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('ffe58f51-bb85-4681-af9d-d232326a30e4', 'Task 4', 'ba2ee26c-ebbb-4d7e-a596-40db9f0711c4')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('ba2ee26c-ebbb-4d7e-a596-40db9f0711c4', 'Task 5', '29189134-8be9-4d93-873e-ce5efefe1c1a')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('29189134-8be9-4d93-873e-ce5efefe1c1a', 'Task 6', NULL)
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('ef069d0a-f2a8-4c9a-8bbc-99ee1e0e2991', 'Task 7', '56a6eb57-ab9f-49cb-875a-a072158b0265')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('56a6eb57-ab9f-49cb-875a-a072158b0265', 'Task 8', 'f8b7cc9b-269e-44c7-85bf-44592d70a21e')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('f8b7cc9b-269e-44c7-85bf-44592d70a21e', 'Task 9', NULL)
and the mapping like this:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="OneToOneIssue.Domain"
assembly="OneToOneIssue.Domain">
<class name="Task" table="`Task`">
<id name="Id" column="Id" type="guid">
<generator class="assigned"/>
</id>
<property name="Description" column="`Description`" />
<many-to-one name="FollowingTask" class="Task" column="FollowingTaskId" />
<one-to-one name="PrecedingTask" class="Task" property-ref="FollowingTask" />
</class>
</hibernate-mapping>
Now if I run a query to get tasks 2, 5 and 8 (the only ones that have a preceding and following task like this:
var tasks = session
.CreateCriteria<Task>()
.Add(Restrictions.In("Description", new string[] {"Task 2", "Task 5", "Task 8"}))
.List<Task>();
Then I get the main query I would expect but also a query each for all of the preceding tasks:
exec sp_executesql N'SELECT this_.Id as Id0_1_, this_.[Description] as Descript2_0_1_, this_.FollowingTaskId as Followin3_0_1_, task2_.Id as Id0_0_, task2_.[Description] as Descript2_0_0_, task2_.FollowingTaskId as Followin3_0_0_ FROM [Task] this_ left outer join [Task] task2_ on this_.Id=task2_.FollowingTaskId WHERE this_.[Description] in (#p0, #p1, #p2)',N'#p0 nvarchar(4000),#p1 nvarchar(4000),#p2 nvarchar(4000)',#p0=N'Task 2',#p1=N'Task 5',#p2=N'Task 8'
exec sp_executesql N'SELECT task0_.Id as Id0_1_, task0_.[Description] as Descript2_0_1_, task0_.FollowingTaskId as Followin3_0_1_, task1_.Id as Id0_0_, task1_.[Description] as Descript2_0_0_, task1_.FollowingTaskId as Followin3_0_0_ FROM [Task] task0_ left outer join [Task] task1_ on task0_.Id=task1_.FollowingTaskId WHERE task0_.FollowingTaskId=#p0',N'#p0 uniqueidentifier',#p0='FFE58F51-BB85-4681-AF9D-D232326A30E4'
exec sp_executesql N'SELECT task0_.Id as Id0_1_, task0_.[Description] as Descript2_0_1_, task0_.FollowingTaskId as Followin3_0_1_, task1_.Id as Id0_0_, task1_.[Description] as Descript2_0_0_, task1_.FollowingTaskId as Followin3_0_0_ FROM [Task] task0_ left outer join [Task] task1_ on task0_.Id=task1_.FollowingTaskId WHERE task0_.FollowingTaskId=#p0',N'#p0 uniqueidentifier',#p0='EF069D0A-F2A8-4C9A-8BBC-99EE1E0E2991'
exec sp_executesql N'SELECT task0_.Id as Id0_1_, task0_.[Description] as Descript2_0_1_, task0_.FollowingTaskId as Followin3_0_1_, task1_.Id as Id0_0_, task1_.[Description] as Descript2_0_0_, task1_.FollowingTaskId as Followin3_0_0_ FROM [Task] task0_ left outer join [Task] task1_ on task0_.Id=task1_.FollowingTaskId WHERE task0_.FollowingTaskId=#p0',N'#p0 uniqueidentifier',#p0='30EFBFDA-F3B5-42FB-906E-098FB32BE79D'
I don't even need the preceding task loaded.
Eager loading the preceding task does not help either.
It does not help if I set the FollowingTask and PrecedingTask to lazy="proxy". It does solve the problem if remove the one-to-one mapping, but this is not a possible solution.
I have seen questions on here about getting round the problem if you need the mapped one-to-one and the answer seems to be that it's a bug and you just have to live with it. However, I do not even need it loaded. I never access it, it just loads for no reason. I believe this question is also unique because of the recursive nature of the relationship.
Is there any way I can prevent it loading or is there another way altogether to achieve the same thing?
Just a suggestion, how to change the mapping. The table structure fits to parent-child schema. We only know that you'd like to have exactly one child.
For parent-child has NHibernate strong support and you won't experience loading of related children any more. So, Instead of <ont-to-one map it like this. c#:
public class Task
{
public virtual Task FollowingTask { get; set; }
public virtual IList<Task> PrecedingTasks { get; set; }
}
mapping hbm:
<many-to-one name="FollowingTask" class="Task" column="FollowingTaskId" />
<bag name="PrecedingTasks">
<key column="FollowingTaskId"></key>
<one-to-many class="Task"/>
</bag>
Now we can even make the IList<Task> PrecedingTasks protected and create Task PrecedingTask property which will handle the get/set access to the first PrecedingTasks list element

LINQ – Nested (address & city) query

I have a problem with a project. I’m trying to get a list of companies that are located in a specific country or city.
Table structure:
Company
CompanyID
CompanyName
etc…
CompanyAddressDetails (relation table)
Company_CompanyID
CorrespondingAddress_AddressID
CorrespondingAddress:
AddressID
StreetName
RegionID
etc…
Region
RegionID
RegionName
RegionRegionTypeID
RegionDetails (relation table)
RegionParent
RegionChild
So to find an address in example Stockholm (which has ID 1198 in the Region table), I would do:
var addresses = from c in db.CorrespondingAddress select c;
addresses = addresses.Where(s => s.RegionID.Equals(1198));
And to find a company in Stockholm I would do:
companyModel = from c in db.Company select c;
companyModel = companyModel.Where(s => s.CorrespondingAddress.Any(x => x.RegionID.Equals(1198)));
But now I want to take into account the RegionDetails table (which has a parent, and child, for example: 1 (Sweden) is parent, and 1198 (Stockholm) is child etc)
How can I do to find a company which is located in Sweden, but has the ID 1198 (Stockholm) in its address row?
In plain SQL I would maybe do something like:
SELECT CompanyName FROM Company
LEFT JOIN CompanyAddressDetails ON (Company.CompanyID = CompanyAddressDetails.Company_CompanyID)
LEFT JOIN CorrespondingAddress ON (CompanyAddressDetails.CorrespondingAddress_AddressID = CorrespondingAddress.AddressID)
LEFT JOIN Region ON (CorrespondingAddress.RegionID = Region.RegionID)
WHERE CorrespondingAddress IN (SELECT RegionChild FROM RegionDetails WHERE RegionParent = 1)
First off, the following code can be refactored into one line:
companyModel = from c in db.Company select c;
companyModel = companyModel.Where(s => s.CorrespondingAddress.Any(x => x.RegionID.Equals(1198)));
Can't you just nest another Any?
companyModel = db.Company.Where(s => s.CorrespondingAddress.Any(x => x.Region.Any(r => r.RegionDetails.Any(rd => rd.Parent == 1 && rd.Child == 1198)));
Edit
Given the following property of CorrespondingAddress:
public virtual Region Region { get; set; }
And assuming Region has a property RegionDetails (making Region -> RegionDetails one-to-one):
public virtual RegionDetails RegionDetails{ get; set; }
The following should work:
companyModel = db.Company.Where(s => s.CorrespondingAddress.Any(x => x.Region.RegionDetails.RegionParent == 1 && x.Region.RegionDetails.RegionChild == 1198)));
since there is no model for the details tables (many-to-many relationship tables), I solved it by using this method:
companyModel = companyModel.Where(s => s.CorrespondingAddress.Any(x => x.Region.RegionParent.Any(d => d.RegionID == region)));

EF 4.3 Code First - Querying a navigation property backwards

I am trying to query a one to many relationship but cannot figure out how to do this. The problem I have is that the ID of the field I want to filter by lives in the join table (not the main table)...
Its probably easier to illustrate rather than explain!!
The two classes I have are
public class DbUserClient
{
public virtual string UserId { get; set; }
public virtual int ClientId { get; set; }
public virtual DateTime AssignedOn { get; set; }
public virtual DateTime? ClearedOn { get; set; }
// navigation properties
public virtual DbUser User { get; set; }
public virtual DbClient Client { get; set; }
}
and
public class DbClient
{
public virtual int ClientId {get;set;}
public virtual string EntityName { get; set; }
public virtual bool Deleted { get; set; }
// navigation properties
public ICollection<DbUserClient> UserClients { get; set; }
}
In the program I have a repository that exposes the Clients i.e.
public ObservableCollection<DbClient> Clients
{
get { return context.Clients.Local; }
}
I am binding to this which is why I am keen on querying via the Client as this will refresh my "Local" collection. However I can't seem to figure out a way to include the UserClients as well as add the "where" clause.
I have tried something like
context.Clients.Include(c => c.UserClients.Where(uc => uc.UserId == "ME"));
But this results in the following exception
"The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Parameter name: path"
This works but unfortunately will not update my "Local" collection
from c in context.Clients
from uc in c.UserClients
where uc.ClientId == uc.ClientId && uc.UserId == "ME"
select new { c.ClientId, c.EntityName, uc.AssignedOn };
Any suggestions on where I have gone wrong?
Cheers
Abs
EDIT I : looking at the SQL Profiler the above query generates the following SQL
SELECT
[Extent1].[ClientId] AS [ClientId],
[Extent1].[EntityName] AS [EntityName],
[Extent2].[AssignedOn] AS [AssignedOn]
FROM [dbo].[Client] AS [Extent1]
INNER JOIN [dbo].[UserClient] AS [Extent2] ON [Extent1].[ClientId] = [Extent2]. [ClientId]
WHERE ([Extent2].[ClientId] = [Extent2].[ClientId]) AND (N'ME' = [Extent2].[UserId])
This is pretty simple and more or less along the lines of what I would have written myself if I was handcrafting the SQL
However although the suggested expression below works and as you pointed out populates the Local cache
context.Clients
.Where(c => c.UserClients.Any(uc => uc.UserId == userId))
.Select(c => new { DbClient = c, DbUser = c.UserClients.Where(uc => uc.UserId == userId).FirstOrDefault() }).ToList();
it produces the following SQL. This looks alot more complicated than it needs to be and I am assuming will have performance implications
exec sp_executesql N'SELECT
[Filter2].[ClientId] AS [ClientId],
[Filter2].[EntityName] AS [EntityName],
[Filter2].[Deleted] AS [Deleted],
[Limit1].[UserId] AS [UserId],
[Limit1].[ClientId] AS [ClientId1],
[Limit1].[AssignedOn] AS [AssignedOn],
[Limit1].[ClearedOn] AS [ClearedOn]
FROM (SELECT [Extent1].[ClientId] AS [ClientId], [Extent1].[EntityName] AS [EntityName], [Extent1].[Deleted] AS [Deleted]
FROM [dbo].[Client] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[UserClient] AS [Extent2]
WHERE ([Extent1].[ClientId] = [Extent2].[ClientId]) AND ([Extent2].[UserId] = #p__linq__0)
) ) AS [Filter2]
OUTER APPLY (SELECT TOP (1)
[Extent3].[UserId] AS [UserId],
[Extent3].[ClientId] AS [ClientId],
[Extent3].[AssignedOn] AS [AssignedOn],
[Extent3].[ClearedOn] AS [ClearedOn]
FROM [dbo].[UserClient] AS [Extent3]
WHERE ([Filter2].[ClientId] = [Extent3].[ClientId]) AND ([Extent3].[UserId] = #p__linq__1) ) AS [Limit1]',N'#p__linq__0 nvarchar(4000),#p__linq__1 nvarchar(4000)',#p__linq__0=N'ME',#p__linq__1=N'ME'
EDIT II : After playing around some more, I have found a solution that seems to fulfill my requirement. Looking at the SQL Profiler, I am happy with the generated SQL. This is similar to that of my orginal query.
exec sp_executesql N'SELECT
[Extent1].[ClientId] AS [ClientId],
[Extent1].[EntityName] AS [EntityName],
[Extent1].[Deleted] AS [Deleted],
[Extent2].[UserId] AS [UserId],
[Extent2].[ClientId] AS [ClientId1],
[Extent2].[AssignedOn] AS [AssignedOn],
[Extent2].[ClearedOn] AS [ClearedOn]
FROM [dbo].[Client] AS [Extent1]
INNER JOIN [dbo].[UserClient] AS [Extent2] ON [Extent1].[ClientId] = [Extent2].[ClientId]
WHERE [Extent2].[UserId] = #p__linq__0',N'#p__linq__0 nvarchar(4000)',#p__linq__0=N'ME'
I am assuming that there is no lazy loading involved here. If someone could confirm I would be grateful
context.Clients.Join
(
context.UserClients,
c => c.ClientId,
uc => uc.ClientId,
(user, usrclient) => new { DbClient = user, DbUserClient = usrclient }
).Where(uc => uc.DbUserClient.UserId == userId).Load();
You can load the clients which have at least one user with UserId = "ME":
var clients = context.Clients
.Where(c => c.UserClients.Any(uc => uc.UserId == "ME"))
.ToList();
This loads the correct clients but no user is included.
If you include the users...
var clients = context.Clients.Include(c => c.UserClients)
.Where(c => c.UserClients.Any(uc => uc.UserId == "ME"))
.ToList();
... you'll get the correctly filtered clients but it will include all users, not only the user "ME".
In order to get the users filtered as well your last approach, the projection, is the best way:
var clientsWithUser = context.Clients
.Where(c => c.UserClients.Any(uc => uc.UserId == "ME"))
.Select(c => new
{
Client = c,
User = c.UserClients.Where(uc => uc.UserId == "ME").FirstOrDefault()
})
.ToList();
This should also update the Local collection because you are loading full entities (Client and User) in the anonymous object list.
Edit
The last query in your question is fine, although it's not really the EF way to write a Join manually when you have navigation properties. The SQL and query result is most likely identical to:
context.UserClients.Include(uc => uc.Client)
.Where(uc => uc.UserId == userId)
.Load();
The Include in this query should translate into the same INNER JOIN that your hand-written LINQ Join produces.

LINQ query fails for NULL values

var query = from t1 in Table1
join t2 in Table2
on new { t1.Id }
equals new { t2.Id}
select new
{
t1.Id,
t1.FirstName,
t1.MiddleName,//allows null values in the database
t1.LastName,
t1.phone //allows null values in the database
};
if(query.Count()>0)//fails here"The value for column MiddleName in table'Table1' is DBNULL"
{
}
Is there a way in which I can get all the rows including null values for middleName and Phone in my LINQ query?
If you are using linq-to-datasets you must manually convert nullable columns to null because their value in DataRow is DBNull.Value. In strongly typed DataSet you should be able to do something like:
var query = from t1 in Table1
join t2 in Table2
on new { t1.Id }
equals new { t2.Id}
select new
{
t1.Id,
t1.FirstName,
t1.IsMiddleNameNull ? null : t1.MiddleName,
t1.LastName,
t1.IsPhoneNull ? null : t1.Phone
};
In untyped DataSet you will call something like t1.IsNull("MiddleName") ? null : t1["MiddleName"]
It sounds like the metadata is out of sync with your DB schema. It seems as if when the classes were generated for your schema MiddleName was not nullable, but now it is. If that's the case, you need to refresh your EDMX if you're using Entity Framework or refresh your classes if you're using LINQ to SQL.
Could you please give this a shot
var query = from t1 in Table1
join t2 in Table2
on new { t1.Id }
equals new { t2.Id}
select new
{
Id = t1.Id,
FirstName = t1.FirstName,
MiddleName = t1.MiddleName,//allows null values in the database
LastName = t1.LastName,
Phone = t1.phone //allows null values in the database
};
if(query.Count()>0)//fails here"The value for column MiddleName in table'Table1' is DBNULL"
{
}
The problem is that a new anonymous object has its properties defined on-the-fly with types inferred from the values.
In such a line
MiddleName = t1.MiddleName,//allows null values in the database
a new property called MiddleName is created whose type is t1.MiddleName's type. But if t1.MiddleName is null, what is the type ??? Null has no type.
To prevent any ambiguousity simply put
MiddleName = (string)t1.MiddleName,
to let the compiler know that anyway it's a string, even if not provided.

Resources