วิธีสร้างบริบทข้อมูล Entity Framework แบบอ่านอย่างเดียว


112

ฉันต้องการเปิดเผยบริบทข้อมูล Entity Framework กับปลั๊กอินของบุคคลที่สาม จุดประสงค์คือเพื่อให้ปลั๊กอินเหล่านี้ดึงข้อมูลเท่านั้นและไม่อนุญาตให้มีปัญหาในการแทรกอัปเดตหรือลบหรือคำสั่งแก้ไขฐานข้อมูลอื่น ๆ ดังนั้นฉันจะสร้างบริบทข้อมูลหรือเอนทิตีแบบอ่านอย่างเดียวได้อย่างไร


3
ให้บริบทกับผู้ใช้ที่ไม่มีสิทธิ์เขียนฐานข้อมูล
vcsjones

ขอบคุณ. ฉันใช้ฐานข้อมูล SQLite เพิ่งพบว่าสามารถเปิดได้ในโหมดอ่านอย่างเดียวผ่านตัวเลือกสตริงการเชื่อมต่อ
Harindaka

2
อย่าให้พวกเขาDbContextให้IQueryableหรือหลายอย่าง
ta.speot.is

คำตอบ:


178

นอกเหนือจากการเชื่อมต่อกับผู้ใช้แบบอ่านอย่างเดียวแล้วยังมีสิ่งอื่น ๆ อีกสองสามอย่างที่คุณสามารถทำได้กับ DbContext ของคุณ

public class MyReadOnlyContext : DbContext
{
    // Use ReadOnlyConnectionString from App/Web.config
    public MyContext()
        : base("Name=ReadOnlyConnectionString")
    {
    }

    // Don't expose Add(), Remove(), etc.
    public DbQuery<Customer> Customers
    {
        get
        {
            // Don't track changes to query results
            return Set<Customer>().AsNoTracking();
        }
    }

    public override int SaveChanges()
    {
        // Throw if they try to call this
        throw new InvalidOperationException("This context is read-only.");
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Need this since there is no DbSet<Customer> property
        modelBuilder.Entity<Customer>();
    }
}

1
เห็นได้ชัดว่าคุณเป็น 'คนใน' :) - สิ่งนี้น่าสนใจกว่าการเชื่อมต่อแบบ 'อ่านอย่างเดียว'
NSGaga ส่วนใหญ่ไม่ได้ใช้งาน

6
โปรดทราบว่าการใช้AsNoTracking()จะทำให้ไม่สามารถใช้การโหลดแบบขี้เกียจได้
Tom Pažourek

@ TomPažourekฉันไม่รู้ว่าเป็นเรื่องจริงหรือเปล่า ... ฉันคิดว่า EF ยังคงสร้างพร็อกซีที่โหลดแบบขี้เกียจ แต่การแก้ปัญหาข้อมูลประจำตัวอาจแปลกไปหน่อย
bricelam

3
อย่าลืมลบล้างpublic override Task<int> SaveChangesAsync()ด้วย
พีท

7
อย่าพึ่งทำแบบนี้เพราะ(context as IObjectContextAdapter).ObjectContext.SaveChanges()จะยังใช้ได้ ทางเลือกที่ดีที่สุดคือการใช้ตัวDbContext(string nameOrConnectionString);สร้างกับสตริงการเชื่อมต่อแบบอ่าน / เขียนสำหรับการสร้างฐานข้อมูลและหลังจากนั้นสตริงการเชื่อมต่อแบบอ่านอย่างเดียว
Jürgen Steinblock

33

เมื่อเทียบกับคำตอบที่ได้รับการยอมรับผมเชื่อว่ามันจะดีกว่าที่จะให้ประโยชน์แก่องค์ประกอบมรดก จากนั้นก็ไม่จำเป็นต้องรักษาวิธีการเช่น SaveChanges เพื่อโยนข้อยกเว้น ยิ่งไปกว่านั้นทำไมคุณต้องมีวิธีการดังกล่าวตั้งแต่แรก? คุณควรออกแบบคลาสในลักษณะที่ผู้บริโภคไม่หลงกลเมื่อดูรายการวิธีการ อินเทอร์เฟซสาธารณะควรสอดคล้องกับเจตนาและเป้าหมายที่แท้จริงของชั้นเรียนในขณะที่ในคำตอบที่ยอมรับการมี SaveChanges ไม่ได้หมายความว่าบริบทเป็นแบบอ่านอย่างเดียว

ในสถานที่ที่ฉันจำเป็นต้องมีบริบทอ่านอย่างเดียวเช่นในด้านอ่านของรูปแบบCQRSฉันใช้การใช้งานต่อไปนี้ ไม่ได้ให้สิ่งอื่นใดนอกจากความสามารถในการสืบค้นแก่ผู้บริโภค

public class ReadOnlyDataContext
{
    private readonly DbContext _dbContext;

    public ReadOnlyDataContext(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IQueryable<TEntity> Set<TEntity>() where TEntity : class
    {
        return _dbContext.Set<TEntity>().AsNoTracking();
    }
}

โดยใช้ ReadOnlyDataContext คุณสามารถเข้าถึงเฉพาะความสามารถในการสืบค้นของ DbContext สมมติว่าคุณมีเอนทิตีชื่อ Order จากนั้นคุณจะใช้อินสแตนซ์ ReadOnlyDataContext ในลักษณะดังต่อไปนี้

readOnlyDataContext.Set<Order>().Where(q=> q.Status==OrderStatus.Delivered).ToArray();

วิธีนี้อนุญาตให้ใช้ db_datareader เฉพาะการล็อกอิน sql หรือไม่ ด้วย DBContext EF มาตรฐานจะปฏิเสธสิทธิ์ CREATE TABLE แม้ว่ารหัสการสืบค้นของฉันจะไม่มี SaveChanges ()
ถึง

2
และทำให้เป็นมรดกจากIDisposable
hkarask

แทนที่จะใช้ Set <> ฉันขอแนะนำ Query <> public IQueryable<TEntity> Get<TEntity>() where TEntity : class { return _dbContext.Query<TEntity>().AsNoTracking(); }
Allan Nielsen

@hkarask - ไม่แน่ใจว่าจะทำอย่างนั้น เนื่องจากการเรียกนี้ไม่ได้สร้าง DbContext จึงไม่ควรกำจัดทิ้ง ซึ่งอาจนำไปสู่การติดตามจุดบกพร่องได้ยากในภายหลัง
Allan Nielsen

@AllanNielsen Query <> ถูกทำเครื่องหมายว่าเลิกใช้แล้ว ตามมันควรใช้ Set <>
Frank
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.