Excluding column from insert - entity-framework-4

Is there a way to map a column in Code First, so that it is populated on select, but not used when inserting or updating?
If I apply the [NotMapped] annotation, the property/column is not populated, but if I do not add this annotation, when inserting, it complains that the column does not exist.
Reason I ask, is that I have a query, that performs a join and returns a value for the column, but on insertion, this column is not needed.
any idea's?
Cheers
Edit:
Just an update to explain in a little more detail what I am doing.
Previously, I had two tables,
Carer
CarerID
UserID
IsPrimary
User
UserID
But then, it was requested that a Carer can belong to more than one User, so I had to create a link table, as below.
UserCarer
UserCarerID
UserID
CarerID
IsPrimary
What I didn't want to do is, is how I've temporarily resolved this, is to create a method within my entity that then initializes another context to get the value.
Instead, I was hoping that when I selected the data, I would perform a left join to get the IsPrimary value from the UserCarer table thus allowing me to keep any reference to Carer.IsPrimary
i.e. select * from Carer.*, UserCarer.IsPrimary from Carer left join UserCarer on Carer.CarerID = UserCarer.CarerID where UserCarer.UserID = #p0
HTH

That is only possible if you mark the column as computed or identity (autogenerated at insert) but it has another consequences - EF will try to select that column after update or insert so if it doesn't exist in your table you will still get an error.
It looks like you are trying to populate class which is not entity and such class cannot be used for persistence! If you have custom join in the query it means that you are doing projection / view of data and the result is most probably not entity = should not be used for saving changes.

Related

How to get IQueryable.ToList() with database fieldnames instead of entity properties

The scenario:
I have a considerable amount of entities as models in CodeFirst mapped to the database fieldname with the Attribute [Column("str")].
I have a bunch of Reporting Service Reports (in local-mode) with the DataSets mapped to the database field names.
I can't pass direct results of linq queries to those reports with the ToList() method because of the field names. What I can do (and I'm trying to avoid) is to type select new for each object; or run each query via a different datasource.
Question:
I would like to know if there is any trick to have a IQueryable object with the original field names instead of the property names. Something like a dynamic select new.
Any suggestions will be appreciated.
No, there isn't. The database column names either have to match the property name, or you have to use the Column attribute to make them line up. That's your only choices.

Gettting the primary key which is autoincrement before saving changes in linqtosql

I am currently using a Dbsetlist.Count() to get the primary key of an Autoincremented table where an Row will be saved before any actual saving is performed.. But I feel this approach is not correct but cannot figure out any other alternative purely using Linq can someone suggest how to do this in Linq only?
db.Invoicesets.Add(invoice); //Invoicesets is Invoice table as list for Linq
order.invno = db.Invoicesets.Count(); // Invno is needed as a foreign for Order table
db.Ordersets.Add(order); //
db.SaveChanges();
Do you mean, say, you want to add entity A first so you can use the identity column of A, A.ID as the FK to entity B? If yes, you can use InsertOnSubmit():
db.Invoicesets.InsertOnSubmit(invoice);
order.invo = invoice;
db.orders.InsertOnSubmit(order);
db.SubmitChanges();
You want to be very careful here. What happens if two threads, at the same time, execute:
order.invno = db.Invoicesets.Count();
You will have two orders with the same invno field, which is probably something you don't want.
I'm guessing that field should have a unique constraint on it, and is perhaps your primary key? I don't think there is any LINQ only way to do this, I think you need to make invno an Identity column, that way you'll be assured that it will increment and remain unique.
EDIT
As an aside, you could also generate a GUID for invno in your application code, but obviously you'll have to change the datatype of the invno field in your db.

2 column table, ignore duplicates on mass insert postgresql

I have a Join table in Rails which is just a 2 column table with ids.
In order to mass insert into this table, I use
ActiveRecord::Base.connection.execute("INSERT INTO myjointable (first_id,second_id) VALUES #{values})
Unfortunately this gives me errors when there are duplicates. I don't need to update any values, simply move on to the next insert if a duplicate exists.
How would I do this?
As an fyi I have searched stackoverflow and most the answers are a bit advanced for me to understand. I've also checked the postgresql documents and played around in the rails console but still to no avail. I can't figure this one out so i'm hoping someone else can help tell me what I'm doing wrong.
The closest statement I've tried is:
INSERT INTO myjointable (first_id,second_id) SELECT 1,2
WHERE NOT EXISTS (
SELECT first_id FROM myjointable
WHERE first_id = 1 AND second_id IN (...))
Part of the problem with this statement is that I am only inserting 1 value at a time whereas I want a statement that mass inserts. Also the second_id IN (...) section of the statement can include up to 100 different values so I'm not sure how slow that will be.
Note that for the most part there should not be many duplicates so I am not sure if mass inserting to a temporary table and finding distinct values is a good idea.
Edit to add context:
The reason I need a mass insert is because I have a many to many relationship between 2 models where 1 of the models is never populated by a form. I have stocks, and stock price histories. The stock price histories are never created in a form, but rather mass inserted themselves by pulling the data from YahooFinance with their yahoo finance API. I use the activerecord-import gem to mass insert for stock price histories (i.e. Model.import columns,values) but I can't type jointable.import columns,values because I get the jointable is an undefined local variable
I ended up using the WITH clause to select my values and give it a name. Then I inserted those values and used WHERE NOT EXISTS to effectively skip any items that are already in my database.
So far it looks like it is working...
WITH withqueryname(first_id,second_id) AS (VALUES(1,2),(3,4),(5,6)...etc)
INSERT INTO jointablename (first_id,second_id)
SELECT * FROM withqueryname
WHERE NOT EXISTS(
SELECT first_id FROM jointablename WHERE
first_id = 1 AND
second_id IN (1,2,3,4,5,6..etc))
You can interchange the Values with a variable. Mine was VALUES#{values}
You can also interchange the second_id IN with a variable. Mine was second_id IN #{variable}.
Here's how I'd tackle it: Create a temp table and populate it with your new values. Then lock the old join values table to prevent concurrent modification (important) and insert all value pairs that appear in the new table but not the old one.
One way to do this is by doing a left outer join of the old values onto the new ones and filtering for rows where the old join table values are null. Another approach is to use an EXISTS subquery. The two are highly likely to result in the same query plan once the query optimiser is done with them anyway.
Example, untested (since you didn't provide an SQLFiddle or sample data) but should work:
BEGIN;
CREATE TEMPORARY TABLE newjoinvalues(
first_id integer,
second_id integer,
primary key(first_id,second_id)
);
-- Now populate `newjoinvalues` with multi-valued inserts or COPY
COPY newjoinvalues(first_id, second_id) FROM stdin;
LOCK TABLE myjoinvalues IN EXCLUSIVE MODE;
INSERT INTO myjoinvalues
SELECT n.first_id, n.second_id
FROM newjoinvalues n
LEFT OUTER JOIN myjoinvalues m ON (n.first_id = m.first_id AND n.second_id = m.second_id)
WHERE m.first_id IS NULL AND m.second_id IS NULL;
COMMIT;
This won't update existing values, but you can do that fairly easily too by using with a second query that does an UPDATE ... FROM while still holding the write table lock.
Note that the lock mode specified above will not block SELECTs, only writes like INSERT, UPDATE and DELETE, so queries can continue to be made to the table while the process is ongoing, you just can't update it.
If you can't accept that an alternative is to run the update in SERIALIZABLE isolation (only works properly for this purpose in Pg 9.1 and above). This will result in the query failing whenever a concurrent write occurs so you have to be prepared to retry it over and over and over again. For that reason it's likely to be better to just live with locking the table for a while.

DB grid : How to use a column of the current row of one as an index into another?

I am not sure if the question title is clear enough, please feel free to edit it.
Basically, I have two DB grids which reflect two database tables, each grid showing one.
When the user selects a row in the first table (let's call it oders), I want to update the second with details of any rows matching a column of the selected row of the first table.
Say, for instance that table orders has a column customer_id and I want to populate the second table (let's call it order_details) with details of all orders from that customer, one order per row.
I can connect up 2 # datasource, query and connection to the two TDbGrids, but I am stuck as to how to code order_details SQL.
The SQL for orders is just SELECT * from orders, but the other?
I want something like SELECT * from order_details WHERE cutomer_id=<orderQuery>.currentRow.FieldByName("customer_id").AsInteger - but I don't know how to do that ...
Can someone help me with some Delphi code?
Also, once I set up that relationship, will selecting a new row in the orders DB grid automatically update the order_details DB grid? Or do I need to add code for that.
P.s I know that there is no books tag anymore (more's the pity), but can someone recommend a good book which explains the fundamentals of programming DB aware controls? I obviously need one. Thanks
Use a parameterized query for the detail (child) database:
SELECT * FROM Order_Details od WHERE od.CustomerID = :CustomerID
Then set the child query's MasterSource to the parent (Order) datasource, and the MasterFields to CustomerID. (If there are multiple columns that link the two, separate them by ;, as in CustomerID;OrderNumber.)
Every time you scroll the parent (change the selected record in the parent DBGrid), the child query will be executed with the ID of the parent row passed as a parameter automatically.

Is it possible to sort a TDBGrid on a lookup field?

I have a DBGrid with a column based on a lookup field.
How can I set it up so that when a user clicks on the column title, it will sort by that field.
My problem here is that I can't figure out a way to create an index on a lookup field.
I'm using Absolute Database for this, but most things that work with the BDE or TClientDataSet will work with Absolute.
Thanks!
I don't think it is possible to create an index on a lookup field. It is possible to create an index on an internally calculated field of a ClientDataSet though. In the OnCalcFields event handler set its value to the value of the lookup field. And set the visible property of the lookup field to false. Now you can sort on the internally calculated field.
What you could do (especially if the data is readonly, and does not have zillions of rows) is use a ClientDataSet to display data in your grid.
Roughly the steps would be like this:
Load the data from your regular into the ClientDataSet,
add a calculated field to the ClientDataSet that contains the value obtained from the lookup,
then add an index to that calculated
field.
--jeroen
You cannot sort by a lookup field. But you can 'fake' this. Let's suppose that you have the following tables: (PK means Primary Key)
Contacts
ID - Integer (PK)
NAME - Varchar(40)
COUNTRYID - Integer
Countries
ID - Integer (PK)
NAME - Varchar(40)
Then you can have the following query in the dataset which is linked to the TDBGrid:
SELECT C.ID, C.NAME, C.COUNTRYID, CO.NAME
FROM CONTACTS C
JOIN COUNTRIES CO ON C.COUNTRYID=CO.ID
(Not tested but I think that you got the idea)
Also you can put this in a view.
Then you'll display in your TDBGrid (as columns) only the ID, NAME and the desired lookup field which you already have (let's call it COUNTRYLOOK).
When one clicks on the Title Header you can change the query by adding in the 4th line an ORDER BY . For the specific column of the lookup field (COUNTRYLOOK), instead of using the 1:1 mapping you can put in the 4th line of your query ORDER BY CO.NAME. Reopen the query and that's it. In practice is much more simpler than my description here.
DevExpress ExpressQuantumGrid can do it, check it out:
http://www.devexpress.com/products/vcl/exquantumgrid/

Resources