我已经创建了两个简单的Grails V3域类,其中location嵌入了父场所中的属性类型,如下所示
import java.time.LocalDate
class Venue {
String name
LocalDate dateCreated
LocalDate lastVisited
LocalDate lastUpdated
GeoAddress location
static hasOne = [location:GeoAddress]
static embedded =['location']
static constraints = {
lastVisited nullable:true
location nullable:true
}
static mapping = {
location cascade: "all-delete-orphan", lazy:false //eager fetch strategy
}
}
class GeoAddress {
String addressLine1
String addressLine2
String addressLine3
String town
String county
String country = "UK"
String postcode
static belongsTo = Venue
static constraints = {
addressLine1 nullable:true
addressLine2 nullable:true
addressLine3 nullable:true
town nullable:true
county nullable:true
country nullable:true
postcode nullable:true
}
}然而,当我写一个集成测试时-我发现为位置创建的级联不起作用(我必须在传递到地点之前保存它不再是瞬态的位置。
此外,当我在启用了flush:true的情况下对地点运行delete操作时,查询地址仍然会得到返回的嵌入式地址-我认为使用flush:true会看到GeoAddress级联删除,但我的测试失败了,因为在使用GeoAddress.get(loc.id)时没有像我预期的那样得到null
@Integration
@Rollback
class VenueIntegrationSpec extends Specification {
void "test venue with an address" () {
when: "create a venue and an address using transitive save on embedded "
GeoAddress address = new GeoAddress (addressLine1: "myhouse", town: "Ipswich", county: "suffolk", postcode : "IP4 2TH")
address.save() //have to save first - else Venue save fails
Venue v = new Venue (name: "bistro", location: address)
def result = v.save()
then: "retrieve venue and check its location loaded eagerly "
Venue lookupVenue = Venue.get(v.id)
GeoAddress loc = lookupVenue.location
loc.postcode == "IP4 2TH"
loc.town == "Ipswich"
when: " we delete the venue, it deletes the embedded location (Address)"
v.delete (flush:true)
GeoAddress lookupLoc = GeoAddress.get (loc.id)
then: "address should disppear"
lookupLoc == null
}我以为我已经正确地设置了它,但是很明显我没有,为什么我的Venue.save()和delete()的级联操作不能级联到我的嵌入式位置(GeoAddress)条目?
发布于 2017-02-06 18:12:53
如果我没理解错的话
cascade: "all-delete-orphan"
仅当您有hasMany=[something:Something]时才需要
在您的例子中,如果我创建这样一个关系,hasOne或GeoAddress location可能是更好的设置。我知道两者之间有一点不同。
无论如何,你的测试都是理论上的。我认为你首先需要捕获错误,以找出为什么它没有级联预期的行为。所以要么
if (!v.delete(flush:true) {
println "--- ${v.errors}"
}或者把它包起来
try catch块
。我在hasMany关系中遇到了类似的问题,这是由于底层hasMany表关系本身的设置而导致与其他表共享记录。诀窍就是从对象本身中删除条目:
lookupVenue .removeFromLocation(loc)
正如我所说的,这是一个hasMany关系
发布于 2017-02-08 06:48:47
非常奇怪,而且太累了,现在想不出来了。我尝试了外部实体和嵌入式-请参阅下面的调整模型。
我写了太多新的测试,两个都能用--但是原来的测试不能。我正在做一些奇怪的事情--只是没有发现它。这两个新的测试做了相同的流程-只是变量不同-两者都有效。所以问题出在第一个测试上。
修改后的测试
@Integration
@Rollback
class VenueIntegrationSpec extends Specification {
def setup() {
}
def cleanup() {
}
//original test - this fails, have to explicitly delete loc to make it work
void "test venue with an address" () {
when: "create a venue and an address using transitive save on embedded "
GeoAddress address = new GeoAddress (addressLine1: "myhouse", town: "Ipswich", county: "suffolk", postcode : "IP4 2TH")
address.save()
Venue v = new Venue (name: "bistro", location: address)
def result = v.save(flush:true)
then: "retrieve venue and check its location loaded eagerly "
Venue lookupVenue = Venue.get(v.id)
GeoAddress loc = lookupVenue.location
loc.postcode == "IP4 2TH"
loc.town == "Ipswich"
when: " we delete the venue, it deletes the embedded location (Address)"
//loc.delete(flush:true)
v.delete (flush:true)
if (v.hasErrors())
println "errors: $v.errors"
GeoAddress lookupLoc = GeoAddress.get (loc.id)
then: "address should disppear"
Venue.get (v.id) == null
lookupLoc == null
}
//new test - external entity - works
void "test with tempLocation" () {
when: ""
TempLocation temp = new TempLocation(name:"will")
Venue v = new Venue (name: "bistro", temp: temp)
assert v.save(flush:true)
Venue lookupVenue = Venue.get(v.id)
TempLocation t = lookupVenue.temp
assert t.name == "will"
//try delete
v.delete (flush:true)
then : " retrieve temp"
TempLocation.findAll().size() == 0
}
//new test - reuse embedded entity - works
void "test with GeoLocation" () {
when: ""
GeoAddress a = new GeoAddress(town:"ipswich")
Venue v = new Venue (name: "bistro", location: a)
assert v.save(flush:true)
Venue lookupVenue = Venue.get(v.id)
GeoAddress ta = lookupVenue.location
assert ta.town == "ipswich"
//try delete
v.delete (flush:true)
then : " retrieve temp"
GeoAddress.findAll().size() == 0
}
}修改了测试中的主题-使用emebbed的Venue.groovy
class Venue {
String name
LocalDate dateCreated
LocalDate lastVisited
LocalDate lastUpdated
GeoAddress location
Collection posts
//test behaviour
TempLocation temp
static hasOne = [location:GeoAddress, temp:TempLocation]
static hasMany = [posts:Post]
static embedded =['location']
static constraints = {
lastVisited nullable:true
location nullable:true, unique:true
posts nullable:true
temp nullable:true //remove later
}
static mapping = {
location cascade: "all-delete-orphan", lazy:false, unique:true //eager fetch strategy
posts sorted: "desc"
temp cascade: "all-delete-orphan", lazy:false, unique:true //remove later
}
}
class GeoAddress {
String addressLine1
String addressLine2
String addressLine3
String town
String county
String country = "UK"
String postcode
static belongsTo = Venue
static constraints = {
addressLine1 nullable:true
addressLine2 nullable:true
addressLine3 nullable:true
town nullable:true
county nullable:true
country nullable:true
postcode nullable:true
}
}用于黑客攻击的地址/位置的新外部版本。带有相同beongsTo/约束逻辑的geoAddress的简化版本
class TempLocation {
String name
//setup birdiectional one to one, cascade owned on venue
static belongsTo = [venue:Venue]
static constraints = {
name nullable:true
}
}我将尝试在火车上重新阅读-不确定为什么第一次测试失败,但下两次工作正常……上床睡觉--太累了
发布于 2017-02-10 07:26:38
我认为这是一个错误的配置。Embedded意味着实体被嵌入到domainclass中。通常这是一个普通的POJO,放在domainclass文件夹之外(在src/groovy文件夹中)。嵌入实体的所有字段都被包括在嵌入实体的表中。hasone设置两个domainclass实体之间的关系。因此,要么使用embedded,要么使用hasOne,但不要同时使用这两种方法。
此外,存在级联保存深度嵌套实体的问题,这在3.2.5中得到了解决。
https://stackoverflow.com/questions/42054344
复制相似问题