locked
Delete Items without Loading RRS feed

  • Question

  • Hello,

    I have the following on my code:

    Pack pack = _repository.Include<Pack>(x => x.Files).First<Pack>(x => x.Id == id);

    I need to delete the files associated to this Pack (One Pack to Many Files Relation) ...

    However, I do not want to load the files because they might be big ... So I changed it to:

    Pack pack = _repository.First<Pack>(x => x.Id == id);

    But how can I know delete the files? I tried the following:

    IList<File> files = _repository.Entry<Pack>(pack).Collection(x => x.Files).Query().Select(x => new File { Id = x.Id }).ToList();

    I am loading the ids of the files without loading other parameters ... But how can I delete the files?

    Thank You,

    Miguel

    Thursday, December 13, 2012 7:26 PM

Answers

  • Hello Fernando,

    Sorry for the delay.

    In the meanwhile I was preparing an example to send to you but I was able to solve this:

    Context context = new Context();
    
    Pack pack = context.Packs.First(x => x.Id == 30);
    
    IList<Int32> ids = context.Entry<Pack>(pack).Collection(x => x.Files).Query().Select(x => x.Id).ToList();
    
    foreach (int id in ids) {
      File file = new File() { Id = id, Pack = pack };
      context.Files.Attach(file);
      context.Files.Remove(file);
    }
    context.SaveChanges();

    When the FK is not defined as a property on the Poco classes I need to add Pack = pack in the File instance.

    Thank You,

    Miguel

    • Marked as answer by MDMoura Wednesday, December 19, 2012 4:48 PM
    Wednesday, December 19, 2012 4:48 PM

All replies

  • Hi Miguel;

    Basically enumerate through the collection of int's create a Pack object attach to its Id the integer in the list then delete the object in the context and when you save changes it will delete from the database.

    foreach( int id in files )
    {
        Pack pack  = new Pack() { Id = id } ; 
        context.AttachTo("Packs", pack);
        context.DeleteObject(pack);
    }
    context.Savechanges();
    

      


    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Thursday, December 13, 2012 9:57 PM
  • Hi Miguel;

    Basically enumerate through the collection of int's create a Pack object attach to its Id the integer in the list then delete the object in the context and when you save changes it will delete from the database.

    foreach( int id in files )
    {
        Pack pack  = new Pack() { Id = id } ; 
        context.AttachTo("Packs", pack);
        context.DeleteObject(pack);
    }
    context.Savechanges();

    A few problems:

    1 - I want to delete the Files not the Pack;

    2 - In EF5 there isn't a AttactTo method or a DeleteObject;

    3 - I tried the closest thing I could find to your code:

          Context context = new Context();
    
          Pack pack = context.Packs.First(x => x.Id == 30);
    
          IList<Int32> ids = context.Entry<Pack>(pack).Collection(x => x.Files).Query().Select(x => x.Id).ToList();
    
          foreach (int id in ids) {
            File file = new File() { Id = id };
            context.Files.Attach(file);
            context.Files.Remove(file);
          }
          context.SaveChanges();

    But I get the following error:

    Entities in 'Context.Files' participate in the 'File_Pack' relationship. 0 related 'File_Pack_Target' were found. 1 'File_Pack_Target' is expected.

    My Pocos are as follows:

      public class Pack {
        public Int32 Id { get; set; }
        public virtual ICollection<File> Files { get; set; }
      } // Pack
    
      public class File {
        public Int32 Id { get; set; }
        public Byte[] Data { get; set; }
        public virtual Pack Pack { get; set; }
      } // File

    And the configuration for both entities are as follows:

    internal class PackMapper : EntityTypeConfiguration<Pack> {
        internal PackMapper() : base() {
          ToTable("Packs");
          HasKey(x => x.Id);
          Property(x => x.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        } // PackMapper
      } // PackMapper
    
    internal class FileMapper : EntityTypeConfiguration<File> {
        internal FileMapper() : base() {
          ToTable("Files");
          HasKey(x => x.Id);
          Property(x => x.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
          Property(x => x.Data).IsOptional();
          HasRequired<Pack>(x => x.Pack).WithMany(y => y.Files).Map(z => { z.MapKey("PackId"); });
        } // FileMapper
      } // FileMapper

    Does anyone knows what I am doing wrong?

    Thank You,

    Miguel

    Thursday, December 13, 2012 10:09 PM
  • Hi Miguel;

    To your statement, "In EF5 there isn't a AttactTo method or a DeleteObject;", that is correct. Seeming you did not supplied version numbers of the EF Visual Studio I assumed ObjectContext and NOT DbContext.

    This code you posted should have worked.

    Context context = new Context();
    
    Pack pack = context.Packs.First(x => x.Id == 30);
    
    IList<Int32> ids = context.Entry<Pack>(pack).Collection(x => x.Files).Query().Select(x => x.Id).ToList();
    
    foreach (int id in ids) {
      File file = new File() { Id = id };
      context.Files.Attach(file);
      context.Files.Remove(file);
    }
    context.SaveChanges();

    Sorry but I dont know why you are getting the exception.

    Are you getting any errors / warnings about using the class name File seeming it may clash with System.IO.File?


    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Friday, December 14, 2012 6:05 AM

  • Sorry but I dont know why you are getting the exception.

    Are you getting any errors / warnings about using the class name File seeming it may clash with System.IO.File?


    No, I am not getting any problems with System.IO.File. I tried the following:

          Context context = new Context();
          Pack pack = context.Packs.Include(x => x.Files).First(x => x.Id == 30);
          foreach (File file in pack.Files) {
            pack.Files.Remove(file);
          }
          context.SaveChanges();

    And I get the following error: Collection was modified; enumeration operation may not execute.

    Then I tried something else (note that I added ToList() to pack.Files:

          Context context = new Context();
          Pack pack = context.Packs.Include(x => x.Files).First(x => x.Id == 30);
          foreach (File file in pack.Files.ToList()) {
            pack.Files.Remove(file);
          }
          context.SaveChanges();

    But I get the following exceptions:

    An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.

    I checked the inner exception and get:

    A relationship from the 'File_Pack' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a corresponding 'File_Pack_Source' must also in the 'Deleted' state."

    Any idea what might be going on here?

    Thank You,

    Miguel

    Friday, December 14, 2012 11:28 AM
  • The last exception in your post is saying you have a constraint issue, you can't delete one without the other. Not sure what is causing it.

    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Friday, December 14, 2012 3:22 PM
  • After a lot of hours I think I was able to isolate the problem:

    I added a FK property to Files and did the mapping as follows:

      Property(x => x.PackId).HasColumnName("PackId").IsRequired();
      HasRequired(x => x.Pack).WithMany(x => x.Files).HasForeignKey(x => x.PackId);

    Then I tried the following which WORKS (it deletes the files):

        Pack pack = context.Packs.First(x => x.Id == 31);
        IList<Int32> ids = context.Entry<Pack>(pack).Collection(x => x.Files).Query().Select(x => x.Id).ToList();
        foreach (int id in ids) {
          File file = new File() { Id = id };
          context.Files.Attach(file);
          context.Files.Remove(file);
        }
        context.SaveChanges();

    Then I replaced the 2 previous configuration code line by the following one so I don't have a FK property in FILE:

    HasRequired<Pack>(x => x.Pack).WithMany(y => y.Files).Map(z => { z.MapKey("PackId"); });

    And I get the following error:

    Entities in 'Context.Files' participate in the 'File_Pack' relationship. 0 related 'File_Pack_Target' were found. 1 'File_Pack_Target' is expected.

    Now, is this something I am doing wrong in configuring an entity without FK property in the class or is this a bug?

    Thank You,

    Miguel

    Friday, December 14, 2012 4:59 PM
  • Hi Miguel;

    Please read this post by Microsoft on Defining and Managing Relationships to see what may be happening.

      


    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Friday, December 14, 2012 6:16 PM
  • Hello,

    I've read that before but I just read it again ... I can't find the reason for my code to not work.

    I have been trying to read everything I can find and in most of the example the following seems fine:

    HasRequired<Pack>(x => x.Pack).WithMany(y => y.Files).Map(z => { z.MapKey("PackId"); });

    Maybe I am missing something but I can't find what ...

    I am using the same code for delete ... But configuring the relation in two ways which both seem right.

    Thank You,

    Miguel

    Friday, December 14, 2012 6:26 PM
  • Hi Miguel;

    If you can zip your project with a test database file that has some data in it I will have a look to see if I can figure out anything. If you wish to do this please post to your SkyDrive and post it here or some other location on the web where I will be able to download it.

      


    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Friday, December 14, 2012 6:49 PM
  • Hello Fernando,

    Sorry for the delay.

    In the meanwhile I was preparing an example to send to you but I was able to solve this:

    Context context = new Context();
    
    Pack pack = context.Packs.First(x => x.Id == 30);
    
    IList<Int32> ids = context.Entry<Pack>(pack).Collection(x => x.Files).Query().Select(x => x.Id).ToList();
    
    foreach (int id in ids) {
      File file = new File() { Id = id, Pack = pack };
      context.Files.Attach(file);
      context.Files.Remove(file);
    }
    context.SaveChanges();

    When the FK is not defined as a property on the Poco classes I need to add Pack = pack in the File instance.

    Thank You,

    Miguel

    • Marked as answer by MDMoura Wednesday, December 19, 2012 4:48 PM
    Wednesday, December 19, 2012 4:48 PM