Làm cách nào tôi có thể nhận Id của thực thể được chèn trong khung Thực thể? [đóng cửa]


611

Tôi gặp sự cố với Entity Framework trong Asp.net. Tôi muốn nhận giá trị Id bất cứ khi nào tôi thêm một đối tượng vào cơ sở dữ liệu. Tôi có thể làm cái này như thế nào?


16
Câu trả lời của Ladislav Mrnka dưới đây là câu trả lời đúng và nên được chấp nhận như vậy.
CShark 17/05/2016

3
OP chỉ đăng một lần với tài khoản của anh ấy / cô ấy, câu hỏi này sẽ cụ thể hơn. Điều này đã cho anh ấy / cô ấy gần 2k danh tiếng (!), Câu trả lời không được đánh dấu là vì đã chấp nhận vì tài khoản bị hủy bỏ kể từ ngày đó.
MurariAlex

1
Nếu bạn chỉ cần Id để sử dụng nó trong mối quan hệ khóa ngoài, bạn có thể xem xét thay vì chỉ đặt thuộc tính điều hướng của thực thể phụ thuộc của mình thành thực thể được thêm trước đó. Bằng cách này, bạn không cần bận tâm về việc gọi SaveChangesngay lập tức chỉ để lấy id. Đọc thêm ở đây .
B12Toaster

Đối với Entity Framework Core 3.0, hãy thêm tham số acceptAllChangesOnSuccess là true: await _context.SaveChangesAsync (true);
Mike

Câu trả lời:


1006

Nó là khá dễ dàng. Nếu bạn đang sử dụng Id được tạo DB (như IDENTITYtrong MS SQL), bạn chỉ cần thêm thực thể vào ObjectSetSaveChangesliên quan ObjectContext. Idsẽ được tự động điền cho bạn:

using (var context = new MyContext())
{
  context.MyEntities.Add(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Yes it's here
}

Entity framework theo mặc định sau mỗi INSERTvới SELECT SCOPE_IDENTITY()khi tự động tạo ra Ids được sử dụng.


34
Vì vậy, bạn đang đặt câu hỏi sai. Nếu bạn gặp vấn đề với ngoại lệ, bạn nên đặt câu hỏi cho thấy ngoại lệ của bạn (và ngoại lệ bên trong) và đoạn mã gây ra lỗi đó.
Ladislav Mrnka

3
. Hãy chắc chắn rằng Entity bạn đang thêm là một thực thể có giá trị như bất cứ điều gì với một hạn chế cơ sở dữ liệu "không rỗng" phải được điền, vv
fran

4
@LadislavMrnka: Còn các thuộc tính điều hướng của đối tượng mới được tạo thì sao? Chúng dường như không được tự động điền sau khi lưu các thay đổi.
Isaac Kleinman

4
Chúng ta hãy xem xét kịch bản sau đây: bảng1 được cho là tạo ra một danh tính @@ để sử dụng nó trong bảng2. Cả bảng1 và bảng2 được cho là trong cùng một giao dịch, ví dụ: một thao tác SaveChange phải lưu cả dữ liệu của bảng. @@ danh tính sẽ không được tạo trừ khi 'SaveChanges' được gọi. Làm thế nào chúng ta có thể giải quyết tình huống này?
Arash

7
@Djeroen: Nếu bạn sử dụng Id được tạo cơ sở dữ liệu, trước tiên bạn cần chèn các đối tượng đó vào cơ sở dữ liệu. Nếu bạn cần phải có Id trước khi chèn, bạn phải xây dựng logic của riêng mình để có Id duy nhất trước khi dữ liệu được chèn và không sử dụng cột định danh trong cơ sở dữ liệu.
Ladislav Mrnka

124

Tôi đã sử dụng câu trả lời của Ladislav Mrnka để lấy thành công Id khi sử dụng Entity Framework tuy nhiên tôi đang đăng ở đây vì tôi đã sử dụng sai (nghĩa là sử dụng nó khi không cần thiết) và nghĩ rằng tôi sẽ đăng những phát hiện của mình ở đây trong- trường hợp mọi người đang tìm cách "giải quyết" vấn đề tôi gặp phải.

Xem xét một đối tượng Đặt hàng có mối quan hệ khóa ngoài với Khách hàng. Khi tôi thêm một khách hàng mới và một đơn đặt hàng mới cùng lúc tôi đang làm một cái gì đó như thế này;

var customer = new Customer(); //no Id yet;
var order = new Order(); //requires Customer.Id to link it to customer;
context.Customers.Add(customer);
context.SaveChanges();//this generates the Id for customer
order.CustomerId = customer.Id;//finally I can set the Id

Tuy nhiên trong trường hợp của tôi, điều này là không bắt buộc vì tôi có mối quan hệ khóa ngoại giữa khách hàng. Tôi và đặt hàng. Khách hàng

Tất cả tôi phải làm là điều này;

var customer = new Customer(); //no Id yet;
var order = new Order{Customer = customer}; 
context.SaveChanges();//adds customer.Id to customer and the correct CustomerId to order

Bây giờ khi tôi lưu các thay đổi, id được tạo cho khách hàng cũng được thêm vào đơn đặt hàng. Tôi không cần các bước bổ sung

Tôi biết điều này không trả lời câu hỏi ban đầu nhưng nghĩ rằng nó có thể giúp các nhà phát triển mới đối với EF không sử dụng quá nhiều câu trả lời được bình chọn hàng đầu cho những điều không cần thiết.

Điều này cũng có nghĩa là các bản cập nhật hoàn tất trong một giao dịch, có khả năng tránh dữ liệu orphin (tất cả các bản cập nhật đã hoàn thành hoặc không có bản cập nhật nào).


8
Cảm ơn ! Mẹo thực hành tốt nhất QUAN TRỌNG: var order = new Order {Khách hàng = khách hàng}; Điều này cho thấy sức mạnh của Entity Framework để gán đối tượng liên quan và Id sẽ tự động được cập nhật.
LA Guy 88

Cảm ơn thông tin bổ sung này cho câu trả lời. Rất hữu ích trong việc lưu vòng tròn DB khi sử dụng EF.
Prasad Korhale

Cám ơn bạn rất nhiều về điều này. Điều này thật đúng với gì mà tôi đã tìm kiếm. Tôi chỉ tin rằng có thể có một cách tốt hơn là gọi "SaveChanges" hai lần
Josh

1
Cũng xin đề cập trong câu trả lời của bạn (tốt nhất là bằng chữ in đậm) rằng điều này giải quyết một hành vi giao dịch. Nếu một trong các đối tượng không thể thêm, một phần của giao dịch sẽ không thành công. Ví dụ: Thêm người và sinh viên. Người thành công và sinh viên thất bại. Bây giờ người là dư thừa. Cảm ơn bạn cho giải pháp tuyệt vời này mặc dù!
Imran Faruqi

32

Bạn cần tải lại thực thể sau khi lưu thay đổi. Bởi vì nó đã bị thay đổi bởi một trình kích hoạt cơ sở dữ liệu không thể được theo dõi bởi EF. Vì vậy, chúng ta cần tải lại thực thể từ DB,

db.Entry(MyNewObject).GetDatabaseValues();

Sau đó

int id = myNewObject.Id;

Nhìn vào câu trả lời @jayantha trong câu hỏi dưới đây:

Làm cách nào tôi có thể nhận Id của thực thể được chèn trong khung Thực thể khi sử dụng defaultValue?

Tìm câu trả lời @christian trong câu hỏi dưới đây cũng có thể giúp:

Entity Framework Làm mới bối cảnh?


2
Xin chào, khi tôi làm như vậy, tôi gặp lỗi biên dịch có nội dung: không thể giải quyết các thuộc tính ví dụ Id hoặc Tên, bạn có thể giúp tôi không?
Morteza Azizi

1
@MortezaAzizi Có vẻ như là lỗi không xử lý hoặc không có vấn đề về tài sản nhưng bạn có thể vui lòng giải thích thêm hoặc viết một số đoạn mã không?
QMaster

3
Không nên làm .GetDatabaseValues();nếu bạn vừa lưu mô hình của mình vào DB. ID sẽ tự động lặp lại mô hình.
vapcguy

3
@QMaster Ngoại trừ việc EF cũng có thể (và không) thực thi chính câu lệnh SQL đó và điền ID của đối tượng của bạn. Nếu không, làm thế nào nó có thể lưu nhiều đối tượng phụ thuộc cùng một lúc? Làm thế nào có thể GetDatabaseValues()nếu nó không biết ID của đối tượng cần tìm trong cơ sở dữ liệu?
krillgar

2
@vapcguy Tôi thấy. Cám ơn heeds của bạn. Tôi sẽ kiểm tra xem trong cả hai phiên bản của EF ASAP.
QMaster

16

Vui lòng tham khảo liên kết này.

http://www.ladislavmrnka.com/2011/03/the-orms-in-storegeneratedpotype-fixed-in-vs-2010-sp1/

Bạn phải đặt thuộc tính của StoreGeneratedPotype để nhận dạng và sau đó thử mã của riêng bạn.

Hoặc nếu không bạn cũng có thể sử dụng này.

using (var context = new MyContext())
{
  context.MyEntities.AddObject(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Your Identity column ID
}

7
Giống như câu trả lời bình chọn hàng đầu.
Lewis86

2
StoreGeneratedPatternlà mảnh còn thiếu cho tôi.
BurnsBA

1
Đó là cách để đi khi làm việc với ORACLE và ON-Chèn Trigger,
Karl

liên kết bị hỏng - tên miền chưa sử dụng
t.durden

Xin chào với Oracle Tôi đã phải thiết lập StoreGeneratedPotype trong Thực thể - đi đến trình xem mô hình, tìm bảng và PK của bạn, chọn thuộc tính StoreGeneratedPotype và đặt thành Nhận dạng. Nó hoạt động như câu trả lời trên chỉ ra. Đây là trường hợp bạn có một trình kích hoạt cư trú PK của bạn từ một chuỗi khi chèn.
Cướp

15

Đối tượng bạn đang lưu phải có chính xác Idsau khi truyền các thay đổi vào cơ sở dữ liệu.


27
Bạn đã nhìn thấy ngoại trừ bên trong? ;-)
Snowbear

6

Bạn chỉ có thể nhận ID sau khi lưu, thay vào đó bạn có thể tạo Hướng dẫn mới và gán trước khi lưu.


4

Tôi gặp một tình huống mà tôi cần chèn dữ liệu vào cơ sở dữ liệu & đồng thời yêu cầu id chính sử dụng khung thực thể. Giải pháp :

long id;
IGenericQueryRepository<myentityclass, Entityname> InfoBase = null;
try
 {
    InfoBase = new GenericQueryRepository<myentityclass, Entityname>();
    InfoBase.Add(generalinfo);
    InfoBase.Context.SaveChanges();
    id = entityclassobj.ID;
    return id;
 }

4

Tất cả các câu trả lời đều rất phù hợp với kịch bản của riêng họ, điều tôi đã làm khác là tôi đã gán int PK trực tiếp từ đối tượng (TEntity) mà Add () trả về một biến int như thế này;

using (Entities entities = new Entities())
{
      int employeeId = entities.Employee.Add(new Employee
                        {
                            EmployeeName = employeeComplexModel.EmployeeName,
                            EmployeeCreatedDate = DateTime.Now,
                            EmployeeUpdatedDate = DateTime.Now,
                            EmployeeStatus = true
                        }).EmployeeId;

      //...use id for other work
}

Vì vậy, thay vì tạo một đối tượng hoàn toàn mới, bạn chỉ cần lấy những gì bạn muốn :)

EDIT cho ông @GertArnold:

nhập mô tả hình ảnh ở đây


3
Thật không hữu ích khi thêm một phương thức không được tiết lộ để gán Id. Điều này thậm chí không liên quan đến Entity Framework.
Gert Arnold

1
@GertArnold .. tôi đã có cùng một câu hỏi như OP tôi tìm thấy câu trả lời và biến nó thành một tuyên bố dòng duy nhất, và tôi chưa bao giờ nghe nói về thuật ngữ phương pháp không tiết lộ chăm sóc để giải thích?
IteratioN7T

3
Điều đó chỉ có nghĩa là bạn không hiển thị (tiết lộ) mọi thứ bạn làm. Có lẽ nó chỉ không được mô tả rõ ràng, tôi không biết. Những gì tôi biết là Add(nếu điều này DbSet.Add) không kỳ diệu gán một giá trị cho EmployeeId.
Gert Arnold

3
Không phải không có SaveChanges. Không thể nào. Trừ khi bạn có một số quy trình khác được gán EmployeeId, ví dụ như trong hàm tạo Employeecủa. HOẶC bạn đang sử dụng lõi EF ForSqlServerUseSequenceHiLo. Dù sao, bạn không đưa ra toàn bộ hình ảnh.
Gert Arnold

3
Nhận xét cuối cùng của tôi sẽ là: đây không phải là hành vi tiêu chuẩn của EF. Bạn nên cung cấp thêm chi tiết về môi trường của bạn. EF phiên bản, thương hiệu cơ sở dữ liệu và phiên bản, class Employee, chi tiết bản đồ của nó.
Gert Arnold

3
Repository.addorupdate(entity, entity.id);
Repository.savechanges();
Var id = entity.id;

Điều này sẽ làm việc.


4
Kho lưu trữ không chịu trách nhiệm lưu các thay đổi vào cơ sở dữ liệu. Đó là công việc của UnitOfWork.
tchelidze

5
Hơn nữa, nó hoàn toàn không rõ Repositorylà gì . Và "điều này sẽ làm việc" là một số lời giải thích!.
Gert Arnold

2

Có hai chiến lược:

  1. Sử dụng cơ sở dữ liệu được tạo ID( inthoặc GUID)

    Nhược điểm:

    Bạn nên thực hiện SaveChanges()để có được các IDthực thể vừa lưu.

    Ưu điểm:

    Có thể sử dụng intdanh tính.

  2. Sử dụng ứng dụng khách được tạo ID- chỉ GUID.

    Ưu điểm: Giảm thiểu SaveChangeshoạt động. Có thể chèn một đồ thị lớn của các đối tượng mới mỗi một thao tác.

    Nhược điểm:

    Chỉ được phép cho GUID


1

Khi bạn sử dụng mã EF 6.x trước tiên

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

và khởi tạo một bảng cơ sở dữ liệu, nó sẽ đặt một

(newsequentialid())

bên trong các thuộc tính bảng dưới tiêu đề Giá trị mặc định hoặc liên kết, cho phép ID được điền khi được chèn.

Vấn đề là nếu bạn tạo một bảng và thêm

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

phần sau, tương lai update-cơ sở dữ liệu sẽ không thêm phía sau (newsequentialid ())

Để khắc phục cách thích hợp là xóa sạch di chuyển, xóa cơ sở dữ liệu và di chuyển lại ... hoặc bạn chỉ có thể thêm (new resultentialid ()) vào trình thiết kế bảng.


Bạn có thể giải thích về việc new resultentialid () đi đâu không? Tôi đã có các mô hình cơ sở dữ liệu được tạo bằng tay, trước tiên không sử dụng mã EF và nó không điền id vì nó không phải là khóa chính của tôi. Rất thích tìm giải pháp cho điều đó.
Josh

1
@josh Giả sử mã đầu tiên là loại Hướng dẫn, nhấp chuột phải vào bảng của bạn trong Sql Server Management Studio, nhấp vào cột Id và bên dưới tab Thuộc tính Cột, bên trong (Chung), bạn sẽ thấy Giá trị mặc định hoặc Liên kết. Nếu bạn đang tạo các bảng DB bằng tay, hãy tham khảo NewSequentialId hoặc NewId . Trường hợp sử dụng chung là đại loại nhưwhen -column- is NULL, then NEWID()
Jeff Li
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.