Чтобы сделать его простым, помните, что фрагмент имеет только одну форму:
s[start:end:step]
и вот как это работает:
s
: объект, который можно нарезать start
: первый индекс для начала итерации end
: последний индекс, ПРИМЕЧАНИЕ, что индекс end
не будет включен в приведенный срез step
: выбрать элемент каждый step
индекс Еще одна вещь для импорта: все start
, end
, step
могут быть опущены ! И если они опущены, их значение по умолчанию будет использовано: 0
, len(s)
, 1
соответственно.
Возможны следующие варианты:
# mostly used variations
s[start:end]
s[start:]
s[:end]
# step related variations
s[:end:step]
s[start::step]
s[::step]
# make a copy
s[:]
ПРИМЕЧАНИЕ: Если start>=end
(учитывая только когда step>0
), python вернет пустой срез []
.
В приведенной выше части объясняются основные функции работы среза, они будут работать в большинстве случаев. Тем не менее, могут возникнуть ошибки, о которых вы должны помнить, и эта часть объясняет их.
Самое первое, что смущает учеников python, - это то, что индекс может быть отрицательным! Не паникуйте: отрицательный индекс означает подсчет с обратной стороны.
Например:
s[-5:] # start at the 5th index from the end of array,
# thus returns the last 5 elements
s[:-5] # start at index 0, end until the 5th index from end of array,
# thus returns s[0:len(s)-5]
Сделать вещи более запутанными в том, что step
также может быть отрицательным!
Отрицательный шаг означает перебрать массив назад: от конца до начала, с включенным индексом конца и начальным индексом, исключенным из результата.
ПРИМЕЧАНИЕ: когда шаг отрицательный, значение по умолчанию для start
- len(s)
(а end
не равно 0
, потому что s[::-1]
содержит s[0]
). Например:
s[::-1] # reversed slice
s[len(s)::-1] # same as above, reversed slice
s[0:len(s):-1] # empty list
Будьте удивлены: срез не увеличивает индекс IndexError, когда индекс выходит за пределы диапазона!
Если индекс находится за пределами допустимого диапазона, python попытается наилучшим образом настроить индекс на 0
или len(s)
в соответствии с ситуацией. Например:
s[:len(s)+5] # same as s[:len(s)]
s[-len(s)-5::] # same as s[0:]
s[len(s)+5::-1] # same as s[len(s)::-1], same as s[::-1]
. Закончим этот ответ примерами, объясняющими все, что мы обсуждали:
# create our array for demonstration
In [1]: s = [i for i in range(10)]
In [2]: s
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: s[2:] # from index 2 to last index
Out[3]: [2, 3, 4, 5, 6, 7, 8, 9]
In [4]: s[:8] # from index 0 up to index 8
Out[4]: [0, 1, 2, 3, 4, 5, 6, 7]
In [5]: s[4:7] # from index 4(included) up to index 7(excluded)
Out[5]: [4, 5, 6]
In [6]: s[:-2] # up to second last index(negative index)
Out[6]: [0, 1, 2, 3, 4, 5, 6, 7]
In [7]: s[-2:] # from second last index(negative index)
Out[7]: [8, 9]
In [8]: s[::-1] # from last to first in reverse order(negative step)
Out[8]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [9]: s[::-2] # all odd numbers in reversed order
Out[9]: [9, 7, 5, 3, 1]
In [11]: s[-2::-2] # all even numbers in reversed order
Out[11]: [8, 6, 4, 2, 0]
In [12]: s[3:15] # end is out of range, python will set it to len(s)
Out[12]: [3, 4, 5, 6, 7, 8, 9]
In [14]: s[5:1] # start > end, return empty list
Out[14]: []
In [15]: s[11] # access index 11(greater than len(s)) will raise IndexError
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]
IndexError: list index out of range
Поскольку эти две строки ...
EmployeeService es = new EmployeeService();
CityService cs = new CityService();
... не принимают параметр в конструкторе, я предполагаю, что вы создаете контекст внутри классов. Когда вы загружаете city1
...
Payroll.Entities.City city1 = cs.SelectCity(...);
... вы присоединяете city1
к контексту в CityService
. Позже вы добавите city1
в качестве ссылки на новый Employee
e1
и добавьте e1
, включая эту ссылку, на city1
в контекст в EmployeeService
. В результате у вас есть city1
, прикрепленный к двум различным контекстам, о которых жалуется исключение.
Вы можете исправить это, создав контекст вне классов обслуживания и введя его и используя его в обеих службах:
EmployeeService es = new EmployeeService(context);
CityService cs = new CityService(context); // same context instance
Ваши классы обслуживания выглядят немного похожими на репозитории, которые отвечают только за один тип сущности. В этом случае у вас всегда будут проблемы, как только будут связаны отношения между сущностями при использовании отдельных контекстов для сервисов.
Вы также можете создать единую службу, которая отвечает за набор тесно связанных объектов , как EmployeeCityService
(который имеет один контекст) и делегирует всю операцию в вашем методе Button1_Click
методу этой службы.
Это старый поток, но другое решение, которое я предпочитаю, просто обновляет cityId и не назначает модель дыры City to Employee ... для этого Employee должен выглядеть так:
public class Employee{
...
public int? CityId; //The ? is for allow City nullable
public virtual City City;
}
Тогда достаточно присвоить:
e1.CityId=city1.ID;
В моем случае я использовал ASP.NET Identity Framework. Я использовал встроенный метод UserManager.FindByNameAsync
для извлечения объекта ApplicationUser
. Затем я попытался ссылаться на этот объект на вновь созданном объекте на другом DbContext
. Это привело к исключению, которое вы изначально видели.
Я решил это, создав новый объект ApplicationUser
только с Id
из метода UserManager
и ссылаясь на этот новый объект.
У меня была та же проблема, и я мог решить создать новый экземпляр объекта, который я пытался обновить. Затем я передал этот объект в свой репозиторий.
У меня была такая же проблема, но моя проблема с решением @ Slauma (хотя и велика в некоторых случаях) заключается в том, что она рекомендует передать контекст в службу, что подразумевает, что контекст доступен из моего контроллера. Это также создает плотную связь между моим контроллером и сервисными слоями.
Я использую Injection Dependency для ввода слоев сервиса / репозитория в контроллер и, как таковой, не имеет доступа к контексту с контроллера.
Мое решение состояло в том, чтобы слои службы / репозитория использовали один и тот же экземпляр контекста - Singleton.
Контекст Singleton Class:
Ссылка: http://msdn.microsoft.com/en-us/library/ff650316.aspx и http://csharpindepth.com/Articles/General/Singleton.aspx
public sealed class MyModelDbContextSingleton
{
private static readonly MyModelDbContext instance = new MyModelDbContext();
static MyModelDbContextSingleton() { }
private MyModelDbContextSingleton() { }
public static MyModelDbContext Instance
{
get
{
return instance;
}
}
}
Класс репозитория:
public class ProjectRepository : IProjectRepository
{
MyModelDbContext context = MyModelDbContextSingleton.Instance;
Существуют другие решения, такие как создание экземпляра контекст один раз и передать его в конструкторы слоев службы / репозитория или другое, о котором я читал, в котором реализуется шаблон «Единица работы». Я уверен, что есть еще ...
Источник ошибки:
ApplicationUser user = await UserManager.FindByIdAsync(User.Identity.Name);
ApplicationDbContext db = new ApplicationDbContent();
db.Users.Uploads.Add(new MyUpload{FileName="newfile.png"});
await db.SavechangesAsync();/ZZZZZZZ
Надеюсь, кто-то сэкономит драгоценное время
Использовать один и тот же объект DBContext во всей транзакции.
Шаги для воспроизведения можно упростить:
var contextOne = new EntityContext();
var contextTwo = new EntityContext();
var user = contexOne.Users.FirstOrDefault();
var group = new Group();
group.User = user;
contextTwo.Groups.Add(group);
contextTwo.SaveChanges();
Код без ошибок:
var context = new EntityContext();
var user = context.Users.FirstOrDefault();
var group = new Group();
group.User = user; // Be careful when you set entity properties.
// Be sure that all objects came from the same context
context.Groups.Add(group);
context.SaveChanges();
В качестве альтернативы инъекции и еще хуже Singleton вы можете вызвать метод Detach до добавления.
EntityFramework 6: ((IObjectContextAdapter)cs).ObjectContext.Detach(city1);
EntityFramework 4: cs.Detach(city1);
Существует еще один способ, если вам не нужен первый объект DBContext. Просто оберните его с помощью ключевого слова:
Payroll.Entities.City city1;
using (CityService cs = new CityService())
{
city1 = cs.SelectCity(Convert.ToInt64(cmbCity.SelectedItem.Value));
}