LINQ - How to read ID which is Autonumber after submitting the data - linq

I am working on LINQ. and in one transaction I have to update three different tables.
e.g A(A1,A2,A3) B(B1,B2) AB(A1,B1)
here B1 is autonumber in my database. I want to submit all the changes together. so in one data context I wrote
using (BBBDataContext DC= new BBBDataContext())
{
A tba = new A()
{
A1 = this.A1,
A2 = this.A2,
A3 = this.A3,
};
DC.A.InsertOnSubmit(tba);
B tbb= new B()
{
B2 = this.B2,
};
DC.B.InsertOnSubmit(tbb);
// NOW i WONT B1(WHICH IS AUTONUMBER) FROM B SO THAT I USE IT IN MY NEXT TABLE.
AB tbab = new AB()
{
A1 = this.A1,
B1 = ??????,
};
DC.AB.InsertOnSubmit(tbab);
//FINALLY I WILL WRITE SUBMIT CHANGES SO MY ALL TABLES GET CHANGES SAME TIME
DC.SubmitChanges();
}
Que: what should I write # the place of ?????. for B1 in AB table??

Short answer: B
Bit longer answer:
When you create the object and add it you won't get the ID before you commit. So what you do is reference the object and not the ID property of the object.
class A {
public int Id { get;set;}
public ICollection <B> Bees { get;set;}
}
class B {
public int Id { get;set;}
public int InstanceOfAId { get;set;}
public A InstanceOfA { get;set;}
}
var a = new A();
var b = new B();
b.InstanceOfA = a;
Depending on your model you will define a relationship. In code first you could do it this way:
EntityTypeConfiguration<B> cfgB = new EntityTypeConfiguration<B>();
cfgB.HasRequired(p => p.InstanceOfA).WithMany(p => p.Bees)
.HasForeignKey(p => p.InstanceOfAId);
In EDMX you can do the same in the designer.
You will use InstanceOfA to assign to when inserting, after that InstanceOfAId will always hold the Id value. When retrieving data InstanceOfA will only be filled when requested.
You can use it like this:
var x = DC.B.Include(p=>p.A);
or
var x = DC.B.Select(p=> new { Id = p.Id, A_Id = p.A.Id});
or
var x = DC.A.Select(p=> new { Id = p.Id, BeeCount = p.Bees.Count()});

Related

decimal? with Left outer join gets null reference in LINQ

I am trying to do left outer join in LINQ for two vars but on selecting required coloumns, I get Object reference not set to an instance of an object error where I want Nullable decimal.
var FLS = (from ee in SumTillFYEnd
join es in SumTillFYStart on ee.Account equals es.Account into temp
from t in temp.DefaultIfEmpty()
select new
{
Account = ee.Account, // As of here it works
BeginDr = (t.DrStartCF == 0) ? (decimal?) null : t.DrStartCF // Here I get error Object reference not set to an instance of an object.
});
Some times SumTillFYEnd and some times SumTillFYStart becomes null. I want to join should work with default values, in case any one or both is null.
The problem is attempting to cast null to decimal?. You cannot ever directly cast null to another type, nullable or not. That will always cause a NullReferenceException. What you want instead is default. In other words, replace:
(decimal?)null
With
default(decimal?)
I solved this using a default class.
The reason I am seeing is that decimal can not be null so it either needs to set for a default value either 0 or decimal.MinValue
So, you require to have default class for SumTillFYStart like
var defaultSumTillFYStart = new SumTillFYStart { Account = string.Empty, DrStartCF =0};
With above in context, then in your piece of code replace
from t in temp.DefaultIfEmpty()
with this
from t in temp.DefaultIfEmpty(defaultSumTillFYStart)
I have a linqPad working written below but for different subset; I think it will help somebody:
void Main()
{
List<Debtor> debtors = new List<Debtor>();
List<SecurityHolding> holdings = new List<SecurityHolding>();
//Initialize Debtor
debtors.Add(new Debtor(){
AccountId = "J1",
OutstandingValue = 501.95M
});
debtors.Add(new Debtor(){
AccountId = "J2",
OutstandingValue = 75.68M
});
debtors.Add(new Debtor(){
AccountId = "J3",
OutstandingValue = 100.01M
});
//Initialize Security Holding
holdings.Add(new SecurityHolding(){
AccountId = "J2",
SecurityHoldingValue = 100M
});
holdings.Add(new SecurityHolding(){
AccountId = "J3",
SecurityHoldingValue = 200M
});
var defaultHolding = new SecurityHolding { AccountId= string.Empty, SecurityHoldingValue = 0};
var result = (from d in debtors
join p in holdings
on d.AccountId equals p.AccountId into temp
from t in temp.DefaultIfEmpty(defaultHolding)
select new
{
AccountId = d.AccountId,
OutstandingValue = d.OutstandingValue,
HoldingValue = (decimal?)t.SecurityHoldingValue
});
result.Dump();
}
// Define other methods and classes here
public class Debtor
{
public string AccountId {get;set;}
public decimal OutstandingValue {get;set;}
}
public class SecurityHolding
{
public string AccountId {get;set;}
public decimal SecurityHoldingValue {get;set;}
}
Here the output:

Entity Framework cycle of data

I have an Account object, which has many Transactions related to it.
In one method, I get all transactions for a particular account.
var transactionlines = (from p in Context.account_transaction
.Include("account_transaction_line")
// .Include("Account")
.Include("account.z_account_type")
.Include("account.institution")
.Include("third_party")
.Include("third_party.z_third_party_type")
.Include("z_account_transaction_type")
.Include("account_transaction_line.transaction_sub_category")
.Include("account_transaction_line.transaction_sub_category.transaction_category")
.Include("z_account_transaction_entry_type")
.Include("account_transaction_line.cost_centre")
where p.account_id == accountId
&& p.deleted == null
select p).ToList();
This is meant to return me a list of transactions, with their related objects. I then pass each object to a Translator, which translates them into data transfer objects, which are then passed back to my main application.
public TransactionDto TranslateTransaction(account_transaction source)
{
LogUserActivity("in TranslateTransaction");
var result = new TransactionDto
{
Id = source.id,
Version = source.version,
AccountId = source.account_id,
// Account = TranslateAccount(source.account, false),
ThirdPartyId = source.third_party_id,
ThirdParty = TranslateThirdParty(source.third_party),
Amount = source.transaction_amount,
EntryTypeId = source.account_transaction_entry_type_id,
EntryType = new ReferenceItemDto
{
Id = source.account_transaction_entry_type_id,
Description = source.z_account_transaction_entry_type.description,
Deleted = source.z_account_transaction_entry_type.deleted != null
},
Notes = source.notes,
TransactionDate = source.transaction_date,
TransactionTypeId = source.account_transaction_type_id,
TransactionType = new ReferenceItemDto
{
Id = source.z_account_transaction_type.id,
Description = source.z_account_transaction_type.description,
Deleted = source.z_account_transaction_type.deleted != null
}
};
... return my object
}
The problem is:
An account has Transactions, and a Transaction therefore belongs to an Account. It seems my translators are being called way too much, and reloading a lot of data because of this.
When I load my transaction object, it's 'account' property has a'transactions' propery, which has a list of all the transactions associated to that account. Each transaction then has an account property... and those account peroprties again, have a list of all the transactions... and on and on it goes.
Is there a way I can limit the loading to one level or something?
I have this set:
Context.Configuration.LazyLoadingEnabled = false;
I was hoping my 'Includes' would be all that is loaded... Don't load 'un-included' related data?
As requested, here is my TranslateAccount method:
public AccountDto TranslateAccount(account p, bool includeCardsInterestRateDataAndBalance)
{
LogUserActivity("in TranslateAccount");
if (p == null)
return null;
var result =
new AccountDto
{
Id = p.id,
Description = p.description,
PortfolioId = p.institution.account_portfolio_id,
AccountNumber = p.account_number,
Institution = TranslateInstitution(p.institution),
AccountType = new ReferenceItemDto
{
Id = p.account_type_id,
Description = p.z_account_type.description
},
AccountTypeId = p.account_type_id,
InstitutionId = p.institution_id,
MinimumBalance = p.min_balance,
OpeningBalance = p.opening_balance,
OpeningDate = p.opening_date
};
if (includeCardsInterestRateDataAndBalance)
{
// Add the assigned cards collection
foreach (var card in p.account_card)
{
result.Cards.Add(new AccountCardDto
{
Id = card.id,
AccountId = card.account_id,
Active = card.active,
CardHolderName = card.card_holder_name,
CardNumber = card.card_number,
ExpiryDate = card.expiry
});
}
// Populate the current interest rate
result.CurrentRate = GetCurrentInterestRate(result.Id);
// Add all rates to the account
foreach (var rate in p.account_rate)
{
result.Rates.Add(
new AccountRateDto
{
Id = rate.id,
Description = rate.description,
Deleted = rate.deleted != null,
AccountId = rate.account_id,
EndDate = rate.end_date,
Rate = rate.rate,
StartDate = rate.start_date
});
}
result.CurrentBalance = CurrentBalance(result.Id);
}
LogUserActivity("out TranslateAccount");
return result;
}
The entity framework context maintains a cache of data that has been pulled out of the database. Regardless of lazy loading being enabled/disabled, you can call Transaction.Account.Transactions[0].Account.Transactions[0]... as much as you want without loading anything else from the database.
The problem is not in the cyclical nature of entity framework objects - it is somewhere in the logic of your translation objects.

What is the faster way to access a DataTable/DataRowsCollection?

I have a datatable with 100,000+ DataRow. Which method is faster to access the collection?
Is there any faster way to process the rows collection ?
Method 1:
var rows= dsDataSet.Tables["dtTableName"].Rows;
int rowCount = dsDataSet.Tables["dtTableName"].Rows.Count;
for (int c = 0; c < rowCount; c++)
{
var theRow = rows[c];
//process the dataRow
}
Method 2:
for (int c = 0; c < dsDataSet.Tables["dtTableName"].Rows.Count; c++)
{
var theRow = dsDataSet.Tables["dtTableName"].Rows[c];
//process the dataRow
}
It is worth noting the most direct way to access cells is via the DataColumn indexer; the data is actually stored in the columns, not the rows (no: really).
So something like:
var table = dataSet.Tables["dtTableName"];
// HERE: fetch the DataColumn of those you need, for example:
var idCol = table.Columns["Id"];
var nameCol = table.Columns["Name"];
// now loop
foreach(DataRow row in table.Rows)
{
var id = (int)row[idCol];
var name = (string)row[nameCol];
// ...
}
However, frankly if you want the best performance, I would start by saying "don't use DataSet / DataTable". That is actually a very complicated model designed to be all kinds of flexible, with change tracking, rule enforcement, etc. If you want fast, I'd use a POCO and something like "dapper", for example:
public class Foo {
public int Id {get;set;}
public string Name {get;set;}
}
...
string region = "North";
foreach(var row in conn.Query<Foo>("select * from [Foo] where Region = #region",
new { region })) // <=== simple but correct parameterisation
{
// TODO: do something with row.Id and row.Name, which are direct
// properties of the Foo row returned
var id = row.Id;
var name = row.Name;
// ...
}
or even skip the type via dynamic:
string region = "North";
foreach(var row in conn.Query("select * from [Foo] where Region = #region",
new { region })) // ^^^ note no <Foo> here
{
// here "row" is dynamic, but still works; not quite as direct as a
// POCO object, though
int id = row.Id; // <=== note we can't use `var` here or the
string name = row.Name; // variables would themselves be "dynamic"
// ...
}

Problem returning an IEnumerable<T>/IList<T>

I am having trouble to return an IEnumerable and IList, I cant do it!
I am using EF 4 with POCOs
Here's the whole method:
//public IList<Genre> GetGenresByGame(int gameId)
public IEnumerable<Genre> GetGenresByGame(int gameId)
{
using(var ctx = new XContext())
{
var results =
from t0 in ctx.GameGenres
join t1 in ctx.GenreCultureDetails on t0.GenreId equals t1.GenreId
where t0.GameId == gameId && t1.CultureId == _cultureId
select new Genre
{
GenreId = t0.GenreId,
GenreName = t1.GenreName
};
return results.ToList();
}
}
I have tried different ways that I have found on the net.. but can't make it work!
Question 2:
I saw a screencast with Julie something, saying that "You should always return an ICollection" when using EF4.
Any thoughts about that ?
BR
EDIT:
When I load the page in Debug-mode i get these errors: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. OR The entity or complex type 'XModel.Genre' cannot be constructed in a LINQ to Entities query.
Genre must not be a L2EF type. Try this:
public IEnumerable<Genre> GetGenresByGame(int gameId)
{
using(var ctx = new XContext())
{
var resultList =
from t0 in ctx.GameGenres
join t1 in ctx.GenreCultureDetails on t0.GenreId equals t1.GenreId
where t0.GameId == gameId && t1.CultureId == _cultureId
select new { t0.GenreId, t1.GenreName };
var genres = resultList.AsEnumerable().Select(o => new Genre
{
GenreId = o.GenreId,
GenreName = o.GenreName
});
return genres.ToList();
}
}
First an foremost if Genre is in the database you should select it? If you have FKs from Genre->GenreCultureDetails let me know and I can update the below, but from the looks of it you could do it like this:
using(var ctx = new XContext())
{
var results =
from g in ctx.Genre
join gcd in ctx.GenreCultureDetails on g.GenreId equals gcd.GenreId
where g.GameId == gameId && gcd.CultureId == _cultureId
select g;
return result.ToList();
}
Alternatively continue down your path select them into an annoynmous type, and then copy them. You can use select instead of convertall if you please.
IList<Genre> returnMe = Null;
using(var ctx = new XContext())
{
var results =
from t0 in ctx.GameGenres
join t1 in ctx.GenreCultureDetails on t0.GenreId equals t1.GenreId
where t0.GameId == gameId && t1.CultureId == _cultureId
select new
{
GenreId = t0.GenreId,
GenreName = t1.GenreName
};
returnMe = results.ToList().ConvertAll(x=>new Genre(){
GenreId = x.GenreId,
GenreName = x.GenreName
}
);
}
return returnMe;

How to select same column's name from different table in Linq?

I've 2 tables with same column's name, for example, both table A and table B has column's name "Test". I want to select column Test from both table A and B to entity class. How can I do this?
It sounds like you want the two entities of TableA and TableB merged into a new object. You can use the .Select() extension method to create a new anonymous type, or into a class that you already have defined.
The requirement here is that you've got to find a common attribute between TableA and TableB. Here I assume you've got something like ID to match them together.
Anonymous Type
var mergedTests = from a in db.TableA
join b in db.TableB on a.CommonID equals b.CommonID
select new
{ TestFromA = a.Test, TestFromB = b.Test }
.ToList();
Existing Class
List<MyCustomTests> mergedTests = from a in db.TableA
join b in db.TableB on a.CommonID equals b.CommonID
select new MyCustomTests
{ TestName= a.Test, ShortName= b.Test }
.ToList();
class Program
{
static void Main(string[] args)
{
var A = new Data[] {
new Data { Test = 1, Relation = 1 },
new Data { Test = 2, Relation = 2 },
new Data { Test = 3, Relation = 3 },
new Data { Test = 4, Relation = 4 },
new Data { Test = 5, Relation = 5 },
};
var B = new Data[] {
new Data { Test = 2, Relation = 2 },
new Data { Test = 3, Relation = 3 },
new Data { Test = 5, Relation = 5 },
};
var res = from a in A
join b in B on a.Relation equals b.Relation
select new { TestA = a.Test, TestB = b.Test };
}
}
class Data
{
public int Test;
public int Relation;
}

Resources