I have recently started using Entity Framework and have run into a problem.
I have 2 simple tables mapped with Entity Framework in my solution:
Employees:
emp_id INT
first_name VARCHAR
last_name VARCHAR
department INT ( FOREIGN KEY MAPPED TO departments.dept_id )
and
Departments:
dept_id INT
department_name VARCHAR
Using the code below, I want to write to the database.
var record = db.employees.Create();
string test = "test";
record.first_name = test;
record.last_name = test;
record.department = 1;
db.employees.Add(record);
db.SaveChanges();
I get an error the error:
Entities in "'DBContextContainer.employees' participate in the 'employeedepartment' relationship. 0 related 'department' were found. 1 'department' is expected."
at the db.SaveChanges() method. Can someone please explain to me how I could resolve or troubleshoot this?
Update: There is a record in the departments table with a dept_id of 1 and I am still getting the error.
You'll need to add a field to the Departments table first since Departments is the parent table (Employees depend on Departments as per your table structure). You cant add an employee with department that doesn't have a corresponding entry in the Departments table.
Related
I have a table called Person with three fields - ID, city and name. City can be null, so I have two partial unique indexes - one on ID and city where city is not null, and one on ID where city is null.
Now I want to have an upsert statement using SQLAlchemy, with those partial indexes, but I can't figure out the syntax. Currently I have:
table = models.Person.__table__
insert_statement = insert(table, upsert_values)
update_dict = {c.name: c for c in insert_statement.excluded if c.name != "id"}
upsert_statement = insert_statement.on_conflict_do_update(
index_elements=[table.c['id'], table.c['city']],
set_=update_dict
)
but when I try to execute I get
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InvalidColumnReference) there is no unique or exclusion constraint matching the ON CONFLICT specification
How can this work? Is there a way other than running pure SQL?
I would like to ask about inserting new record into table through entity framework. I have composited primary key (id and department_id). Department_Id is constant because there are departments and each department can create new record. Each record is replicated to all departments. Id is identity by department. But it cannot be identity on column because when all departments can create record with Id=1 but department_id will be different.
Now I solve it that I create new record in dummy table which has identity column and I get this value into Id column and save record. So for each table I have specialized table with identity column to generated Id value.
Table Customer (Id int, Department_Id int, …) Id, Department_Id is primary key.
Table CustomerIdentity(Id int identity(1,1), Dummy int null).
I have stored procedure to save new record:
declare #id int
declare #department_id int = 10 -- constant for department 10
insert into CustomerIdentity(Dummy) values (null)
set #id = scope_identity()
insert into Customer(Id, Department_Id, …) values (#id, #department_id, …)
I refactor this code to extract logic from stored procedure to C# where I have Customer entity. Id cannot be identity because there could be records as:
Id | Department_Id
1 | 1 -- record from department 1.
1 | 2 -- record from department 2.
1 | N -- record from department N.
So there is Identity table which holds identity value for each department. Each record from department 1..N is replicated to all departments.
How to set EF to give value for Id column from another table?
To do something with EF I would look at something like:
using (var context = new MyDbContext())
{
var customerIdentity = new CustomerIdentity();
context.CustomerIdentities.Add(customerIdentity);
context.SaveChanges();
var newCustomer = new Customer
{
DepartmentId = _DepartmentId, // I.e. "10"
CustomerId = customerIdentity.CustomerId
// ...
}
// Optionally you could delete the CustomerIdentity record.
context.CustomerIdentities.Remove(customerIdentity);
context.SaveChanges();
}
This assumes that each department will have its own database which would manage its own identity tables for the ids, but would be synchronized with other databases or a central database where data cross departments would be queried. The CustomerIdentity provides the sequence (autoincrement) for the IDs, so once that is retrieved (first SaveChanges call) and earmarked into the Customer record, the CustomerIdentity record can be deleted. The table would remain empty but the Identity would continue to increment. If you decide to keep the CustomerIdentity row you would want to avoid associating the Customer and CustomerIdentity entities in a relationship in EF even though for a department they would form a 1 to 1 relationship. Other departments identity counters could be higher and such a relationship would result in errors if the target database had identity up to say 50, and a record wants to get added with an ID of 65. Identity 65 doesn't yet exist so EF would throw a FK violation if you try to bring that customer record in.
I have to insert data to db in form fields that have the same path and i want to save it different id's but rather it concatenated it with ",", how could i possibly do it?
I tried to make some alias in SQL but it saves into same db field name with concatenated with ","
i expected in db when i insert that
EX.
db field name = description
input 1 value = "john";
input 2 value = "doe";
id description
1 john
2 doe
above is my expected result
but in my case when i insert it shows these
id description
1 john,doe
can someone help me to achieve that result ? THANKYOU!
Let me present a similar situation. You have a database of people and you are concerned that each person might have multiple phone numbers.
CREATE TABLE Persons (
person_id INT UNSIGNED AUTO_INCREMENT,
...
PRIMARY KEY(person_id) );
CREATE TABLE PhoneNumbers (
person_id INT UNSIGNED,
phone VARCHAR(20) CHARACTER SET ascii,
type ENUM('unknown', 'cell', 'home', 'work'),
PRIMARY KEY(person_id, phone) );
The table PhoneNumbers has a "many-to-1" relationship between phone numbers and persons. (It does not care if two persons share the same number.)
SELECT ...
GROUP CONCAT(pn.phone) AS phone_numbers,
...
FROM Persons AS p
LEFT JOIN PhoneNumbers AS pn USING(person_id)
...;
will deliver a commalist of phone numbers (eg: 123-456-7890,333-444-5555) for each person being selected. Because of the LEFT, it will deliver NULL in case a person has no associated phones.
To address your other question: It is not practical to split a commalist into the components.
Hi I have M:M relationship between two tables, Contacts and Tags and their M:M table is called Contacts_Tags:
Contacts
------------
ID
Name
Tags
-----------
ID
Name
Contacts_Tags
--------------
Contact_ID
Tag_ID
I have entities for Contacts called Contact and for Tags called Tag but not for Contacts_Tags table.
I want to left join in query builder
$queryBuilder = $this->entityManager->getRepository(Contact::class)->createQueryBuilder("o")->select("o");
$queryBuilder->leftJoin(//here, "et", "WITH", "et.Contact_ID = o.ID")
->leftJoin(Tag::class, "t", "WITH", "t.ID = et.Tag_ID")
;
But I cannot figure out how to add it. I tried documentations but it says to add Entity when I add entity of ContactTag it throws error that entity should have primary key.
Any idea?
To do left join :
$queryBuilder->join(table, condition, columns, $queryBuilder::JOIN_LEFT);
with :
table is the name of a table or another Select or array [alias => table]
condition is a string (the same as in Sql language)
columns is an array like [alias => column_name, ...] or [column_name, ...], may be empty
$queryBuilder is a Select, can be replaced by \Zend\Sql\Select::JOIN_LEFT
I've created entity data model for the following database tables in SqlCe:
CREATE TABLE [test_vulnerabilities] (
[id] INTEGER PRIMARY KEY,
[description] NTEXT NOT NULL DEFAULT ''
);
CREATE TABLE [test_software_vulnerabilities]
(
[id] INTEGER PRIMARY KEY IDENTITY,
[vulnerability_id] INTEGER NOT NULL
REFERENCES [test_vulnerabilities]([id]),
[details] NTEXT NOT NULL DEFAULT ''
);
Entities (created by adding entity model based on existing database):
entity Vulnerability in set Vulnerabilities
Id int
Description string
Software ICollection<SoftwareVulnerability> - navigation property
entity SoftwareVulnerability in set SoftwareVulnerabilities
Id int
Details string
VulnerabilityId int
Vulnerability Vulnerability - navigation property
and executing the following query:
var query = (from v in entities.Vulnerabilities.Include("Software")
where v.Id == id && v.Software.Count > 0
select v);
it is very-very-very slow because the generated SQL joins vulnerabilities with software_vulnerability with left outer join.
Is there any way to simply say that I want only vulnerabilities with non-empty software_vulnerability and the INNER JOIN is ok?
Thanks!
No. You don't have control over used joins. You can try to revert the query:
var query = (from s in entities.SofwareVulnerabilities.Include("Vulnerability")
where s.VulnerabilityId == id
select s);
You will get all software vulnerabilities for your single expected vulnerability and the vulnerability will be included. If your relation is from software vulnerability is correctly configured as mandatory it should hopefully use inner join.
I think this may be slow because you are using count. I would just try .Any() here instead as it will probably be a heap faster